From 96f0efa04eb2b394c3b97dc598df900be42b9593 Mon Sep 17 00:00:00 2001 From: abaskk-msft Date: Fri, 28 Jun 2024 12:09:02 -0700 Subject: [PATCH 1/3] Clean yaml validator false positive output (#682) --- src/YamlValidator/ValidatorResults.cs | 61 ++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/YamlValidator/ValidatorResults.cs b/src/YamlValidator/ValidatorResults.cs index f396d34b..e7565148 100644 --- a/src/YamlValidator/ValidatorResults.cs +++ b/src/YamlValidator/ValidatorResults.cs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. +using System.Collections.ObjectModel; + namespace Microsoft.PowerPlatform.PowerApps.Persistence.YamlValidator; public class ValidatorResults { @@ -10,6 +12,63 @@ public class ValidatorResults public ValidatorResults(bool schemaValid, IReadOnlyList traversalResults) { SchemaValid = schemaValid; - TraversalResults = traversalResults; + TraversalResults = FilterErrors(traversalResults); + } + + // This will filter out the false positives that are not relevant to the error output, when the validation is false + private ReadOnlyCollection FilterErrors(IReadOnlyList traversalResults) + { + var maxSchemaArraySuffixSize = 0; + var maxSchemaObjectSuffixSize = 0; + var arrayTypeSchemaPath = "/oneOf/1"; + var objectTypeSchemaPath = "/oneOf/0"; + foreach (var err in traversalResults) + { + var errSchemaPath = err.SchemaPath; + if (!errSchemaPath.StartsWith(arrayTypeSchemaPath, StringComparison.Ordinal) && + !err.SchemaPath.StartsWith(objectTypeSchemaPath, StringComparison.Ordinal)) + { + continue; + } + + var suffixLength = errSchemaPath.Length - arrayTypeSchemaPath.Length; + if (errSchemaPath.StartsWith(arrayTypeSchemaPath, StringComparison.Ordinal)) + { + maxSchemaArraySuffixSize = Math.Max(maxSchemaArraySuffixSize, suffixLength); + } + else + { + maxSchemaObjectSuffixSize = Math.Max(maxSchemaObjectSuffixSize, suffixLength); + } + } + var filteredErrors = new List(); + foreach (var err in traversalResults) + { + var errSchemaPath = err.SchemaPath; + if (!errSchemaPath.StartsWith(arrayTypeSchemaPath, StringComparison.Ordinal) && + !err.SchemaPath.StartsWith(objectTypeSchemaPath, StringComparison.Ordinal)) + { + filteredErrors.Add(err); + continue; + } + + if (errSchemaPath.StartsWith(arrayTypeSchemaPath, StringComparison.Ordinal)) + { + if (maxSchemaArraySuffixSize >= maxSchemaObjectSuffixSize) + { + filteredErrors.Add(err); + } + } + else + { + if (maxSchemaObjectSuffixSize >= maxSchemaArraySuffixSize) + { + filteredErrors.Add(err); + } + } + + } + + return filteredErrors.AsReadOnly(); } } From e2da260f36866132401b7cea119ae286925bfe89 Mon Sep 17 00:00:00 2001 From: Crash Collison <3751389+tehcrashxor@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:42:19 -0700 Subject: [PATCH 2/3] Return Formulas.Tools to netstandard2.0 (#684) --- src/Directory.Build.props | 1 - src/PAModel/Checksum/ChecksumMaker.cs | 3 +- src/PAModel/IsExternalInit.cs | 25 ++++ ...rosoft.PowerPlatform.Formulas.Tools.csproj | 6 +- .../PAConvert/Parser/CharacterUtils.cs | 3 +- src/PAModel/PAConvert/Yaml/YamlLexer.cs | 5 +- src/PAModel/Serializers/MsAppSerializer.cs | 2 +- src/PAModel/packages.lock.json | 130 ++++++++++-------- .../Persistence.Tests.csproj | 1 + ...PowerPlatform.PowerApps.Persistence.csproj | 4 + 10 files changed, 115 insertions(+), 65 deletions(-) create mode 100644 src/PAModel/IsExternalInit.cs diff --git a/src/Directory.Build.props b/src/Directory.Build.props index a4da0e30..4ff43d99 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -39,7 +39,6 @@ - diff --git a/src/PAModel/Checksum/ChecksumMaker.cs b/src/PAModel/Checksum/ChecksumMaker.cs index 38f095d9..ccd16014 100644 --- a/src/PAModel/Checksum/ChecksumMaker.cs +++ b/src/PAModel/Checksum/ChecksumMaker.cs @@ -225,6 +225,7 @@ internal static int GetChecksumVersion(string checksum) // Formula whitespace can differ between platforms, and leading whitespace // is affected by writing to .pa format. Normalize so checksums are // platform independent + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0056:Use index operator", Justification = "Not available in netstandard2.0")] internal static string NormFormulaWhitespace(string s) { var sb = new StringBuilder(); @@ -247,7 +248,7 @@ internal static string NormFormulaWhitespace(string s) } } // Don't include trailing whitespace - while ((sb.Length > 1) && sb[^1] == ' ') { sb.Length--; } + while ((sb.Length > 1) && sb[sb.Length - 1] == ' ') { sb.Length--; } return sb.ToString(); } diff --git a/src/PAModel/IsExternalInit.cs b/src/PAModel/IsExternalInit.cs new file mode 100644 index 00000000..c17deffc --- /dev/null +++ b/src/PAModel/IsExternalInit.cs @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#if NETFRAMEWORK || NETSTANDARD2_0 +#pragma warning disable + +using System.ComponentModel; + +namespace System.Runtime.CompilerServices; + +// C# 9 init property setters and record types do not quite function out-of-the-box +// for net4.8, but do so long as an "System.Runtime.CompilerServices.IsExternalInit" +// type merely exists. +[EditorBrowsable(EditorBrowsableState.Never)] +#if TFMADAPTERS_PUBLIC +public +#else +internal +#endif +static class IsExternalInit +{ +} + +#pragma warning restore +#endif diff --git a/src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj b/src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj index 138e4cb6..9cdae48f 100644 --- a/src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj +++ b/src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj @@ -1,6 +1,8 @@ + netstandard2.0;net8.0 + 12 Microsoft.PowerPlatform.Formulas.Tools Microsoft.PowerPlatform.Formulas.Tools @@ -49,8 +51,4 @@ - - - - diff --git a/src/PAModel/PAConvert/Parser/CharacterUtils.cs b/src/PAModel/PAConvert/Parser/CharacterUtils.cs index 44c8691f..24483699 100644 --- a/src/PAModel/PAConvert/Parser/CharacterUtils.cs +++ b/src/PAModel/PAConvert/Parser/CharacterUtils.cs @@ -119,11 +119,12 @@ public static bool IsLineTerm(char ch) return false; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0056:Use index operator", Justification = "Not available in netstandard2.0")] public static string UnEscapeName(string name, ErrorContainer errors) { if (IsIdentDelimiter(name[0])) { - if (!IsIdentDelimiter(name[^1])) + if (!IsIdentDelimiter(name[name.Length - 1])) { // Must match errors.ParseError(default, $"Unmatched escape delimeter in {name}"); diff --git a/src/PAModel/PAConvert/Yaml/YamlLexer.cs b/src/PAModel/PAConvert/Yaml/YamlLexer.cs index d0056a04..7b076b4e 100644 --- a/src/PAModel/PAConvert/Yaml/YamlLexer.cs +++ b/src/PAModel/PAConvert/Yaml/YamlLexer.cs @@ -473,6 +473,7 @@ private SourceLocation LocWorker(int startIndex1, int endIndex1) // https://yaml-multiline.info/ + [System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE0056:Use index operator", Justification = "Not available in netstandard2.0")] private string ReadMultiline(int multilineMode) { var sb = new StringBuilder(); @@ -513,7 +514,7 @@ private string ReadMultiline(int multilineMode) { while (true) { - if (sb.Length > 0 && sb[^1] == '\n') + if (sb.Length > 0 && sb[sb.Length - 1] == '\n') { sb.Length--; } @@ -521,7 +522,7 @@ private string ReadMultiline(int multilineMode) { break; } - if (sb.Length > 0 && sb[^1] == '\r') + if (sb.Length > 0 && sb[sb.Length - 1] == '\r') { sb.Length--; } diff --git a/src/PAModel/Serializers/MsAppSerializer.cs b/src/PAModel/Serializers/MsAppSerializer.cs index 2a5f840a..1df71654 100644 --- a/src/PAModel/Serializers/MsAppSerializer.cs +++ b/src/PAModel/Serializers/MsAppSerializer.cs @@ -57,7 +57,7 @@ private static string AsString(ZipArchiveEntry entry) public static CanvasDocument Load(Stream streamToMsapp, ErrorContainer errors) { - ArgumentNullException.ThrowIfNull(streamToMsapp); + _ = streamToMsapp ?? throw new ArgumentNullException(nameof(streamToMsapp)); // Read raw files. // Apply transforms. diff --git a/src/PAModel/packages.lock.json b/src/PAModel/packages.lock.json index 2a2f8c6d..2479ac3a 100644 --- a/src/PAModel/packages.lock.json +++ b/src/PAModel/packages.lock.json @@ -1,13 +1,22 @@ { "version": 1, "dependencies": { - "net8.0": { + ".NETStandard,Version=v2.0": { "Microsoft.Net.Compilers.Toolset.Framework": { "type": "Direct", "requested": "[4.10.0-3.24216.12, )", "resolved": "4.10.0-3.24216.12", "contentHash": "Y1T1ZN3cHWToRYZHhRs8xby1tMCkF23Jb//zK+Tdf4ourzwbMQ4GiTRVVFAlWvmA10iVNUyCZucAeLt5XeiDqA==" }, + "NETStandard.Library": { + "type": "Direct", + "requested": "[2.0.3, )", + "resolved": "2.0.3", + "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0" + } + }, "Newtonsoft.Json": { "type": "Direct", "requested": "[13.0.1, )", @@ -20,6 +29,8 @@ "resolved": "6.0.0", "contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==", "dependencies": { + "System.Buffers": "4.5.1", + "System.Memory": "4.5.4", "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, @@ -29,8 +40,13 @@ "resolved": "6.0.0", "contentHash": "zaJsHfESQvJ11vbXnNlkrR46IaMULk/gHxYsJphzSF+07kTjPHv+Oc14w6QEOfo3Q4hqLJgStUaYB9DBl0TmWg==", "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0", + "System.Buffers": "4.5.1", + "System.Memory": "4.5.4", + "System.Numerics.Vectors": "4.5.0", "System.Runtime.CompilerServices.Unsafe": "6.0.0", - "System.Text.Encodings.Web": "6.0.0" + "System.Text.Encodings.Web": "6.0.0", + "System.Threading.Tasks.Extensions": "4.5.4" } }, "YamlDotNet": { @@ -42,88 +58,92 @@ "Microsoft.Bcl.AsyncInterfaces": { "type": "Transitive", "resolved": "6.0.0", - "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" - }, - "Microsoft.Extensions.DependencyInjection": { - "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + "System.Threading.Tasks.Extensions": "4.5.4" } }, - "Microsoft.Extensions.DependencyInjection.Abstractions": { + "Microsoft.NETCore.Platforms": { "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==" + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" }, - "Microsoft.Extensions.Logging": { + "System.Buffers": { "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection": "8.0.0", - "Microsoft.Extensions.Logging.Abstractions": "8.0.0", - "Microsoft.Extensions.Options": "8.0.0" - } + "resolved": "4.5.1", + "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==" }, - "Microsoft.Extensions.Logging.Abstractions": { + "System.Memory": { "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==", + "resolved": "4.5.4", + "contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==", "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + "System.Buffers": "4.5.1", + "System.Numerics.Vectors": "4.4.0", + "System.Runtime.CompilerServices.Unsafe": "4.5.3" } }, - "Microsoft.Extensions.Options": { + "System.Numerics.Vectors": { "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==", - "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0", - "Microsoft.Extensions.Primitives": "8.0.0" - } + "resolved": "4.5.0", + "contentHash": "QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==" }, - "Microsoft.Extensions.Primitives": { + "System.Runtime.CompilerServices.Unsafe": { "type": "Transitive", - "resolved": "8.0.0", - "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g==" + "resolved": "6.0.0", + "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" }, - "Microsoft.PowerFx.Core": { + "System.Threading.Tasks.Extensions": { "type": "Transitive", - "resolved": "1.2.0", - "contentHash": "M9DY6FqWUXUPgjbbHsB3vt7+b4QPFaoKBZ7ixSU7cPgHKzo/aNohzYWxYasXwTV6pamv5gX9AqLuF13RimMPdg==", + "resolved": "4.5.4", + "contentHash": "zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==", "dependencies": { - "Microsoft.Bcl.AsyncInterfaces": "6.0.0", - "Microsoft.PowerFx.Transport.Attributes": "1.2.0", - "System.Collections.Immutable": "6.0.0" + "System.Runtime.CompilerServices.Unsafe": "4.5.3" } + } + }, + "net8.0": { + "Microsoft.Net.Compilers.Toolset.Framework": { + "type": "Direct", + "requested": "[4.10.0-3.24216.12, )", + "resolved": "4.10.0-3.24216.12", + "contentHash": "Y1T1ZN3cHWToRYZHhRs8xby1tMCkF23Jb//zK+Tdf4ourzwbMQ4GiTRVVFAlWvmA10iVNUyCZucAeLt5XeiDqA==" }, - "Microsoft.PowerFx.Transport.Attributes": { - "type": "Transitive", - "resolved": "1.2.0", - "contentHash": "zlvi59W/4MdDJeR2rIL8k633V+FIHtxbhyaurNBZevksNWCZ49AV0bUhpB6cUjD/vwci8ZXXWziw0yYnjXIzNg==" + "Newtonsoft.Json": { + "type": "Direct", + "requested": "[13.0.1, )", + "resolved": "13.0.1", + "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" }, - "System.Collections.Immutable": { - "type": "Transitive", + "System.Text.Encodings.Web": { + "type": "Direct", + "requested": "[6.0.0, )", "resolved": "6.0.0", - "contentHash": "l4zZJ1WU2hqpQQHXz1rvC3etVZN+2DLmQMO79FhOTZHMn8tDRr+WU287sbomD0BETlmKDn0ygUgVy9k5xkkJdA==", + "contentHash": "Vg8eB5Tawm1IFqj4TVK1czJX89rhFxJo9ELqc/Eiq0eXy13RK00eubyU6TJE6y+GQXjyV5gSfiewDUZjQgSE0w==", "dependencies": { "System.Runtime.CompilerServices.Unsafe": "6.0.0" } }, + "System.Text.Json": { + "type": "Direct", + "requested": "[6.0.0, )", + "resolved": "6.0.0", + "contentHash": "zaJsHfESQvJ11vbXnNlkrR46IaMULk/gHxYsJphzSF+07kTjPHv+Oc14w6QEOfo3Q4hqLJgStUaYB9DBl0TmWg==", + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0", + "System.Text.Encodings.Web": "6.0.0" + } + }, + "YamlDotNet": { + "type": "Direct", + "requested": "[15.1.6, )", + "resolved": "15.1.6", + "contentHash": "T/cQEK/KHK96Q8kytJ4iUGDXg1/fj2Qtk6rCQeIlHYU1zTeyGVHW0QNZgREQyxZpygGMDMmrXNWt0sj5TsQnjA==" + }, "System.Runtime.CompilerServices.Unsafe": { "type": "Transitive", "resolved": "6.0.0", "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==" - }, - "microsoft.powerplatform.powerapps.persistence": { - "type": "Project", - "dependencies": { - "Microsoft.Extensions.Logging": "[8.0.0, )", - "Microsoft.PowerFx.Core": "[1.2.0, )", - "YamlDotNet": "[15.1.6, )" - } } } } diff --git a/src/Persistence.Tests/Persistence.Tests.csproj b/src/Persistence.Tests/Persistence.Tests.csproj index 15df682c..b782c3ba 100644 --- a/src/Persistence.Tests/Persistence.Tests.csproj +++ b/src/Persistence.Tests/Persistence.Tests.csproj @@ -38,6 +38,7 @@ + diff --git a/src/Persistence/Microsoft.PowerPlatform.PowerApps.Persistence.csproj b/src/Persistence/Microsoft.PowerPlatform.PowerApps.Persistence.csproj index 9465881b..7dd196a8 100644 --- a/src/Persistence/Microsoft.PowerPlatform.PowerApps.Persistence.csproj +++ b/src/Persistence/Microsoft.PowerPlatform.PowerApps.Persistence.csproj @@ -35,6 +35,10 @@ $(NoWarn);NU1601 + + + + From 521ab796e7b4d55a5b676c99aad1f05e8089949d Mon Sep 17 00:00:00 2001 From: Crash Collison <3751389+tehcrashxor@users.noreply.github.com> Date: Fri, 28 Jun 2024 15:25:34 -0700 Subject: [PATCH 3/3] Fix framework multitargeting (#688) --- src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj b/src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj index 9cdae48f..213c4f39 100644 --- a/src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj +++ b/src/PAModel/Microsoft.PowerPlatform.Formulas.Tools.csproj @@ -7,6 +7,13 @@ Microsoft.PowerPlatform.Formulas.Tools + + + + + $(OutDir)\$(TargetFramework) + + Microsoft.PowerPlatform.Formulas.Tools