From 801ab18c0ce420d9c7a920cfdbe073eadfdd6884 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 22:23:00 +0000 Subject: [PATCH 1/3] Initial plan From 96f16baf80a26f4055b443a832616d6cff08d1cb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Mar 2026 22:29:53 +0000 Subject: [PATCH 2/3] Move manifest retrieval into separate SlnxXsdProvider class Co-authored-by: 304NotModified <5808377+304NotModified@users.noreply.github.com> --- .../ServiceCollectionExtensions.cs | 1 + .../Validation/SlnxXsdProvider.cs | 16 ++++++++++++++++ .../Validation/XsdValidator.cs | 10 ++-------- .../SlnxValidatorTests.cs | 2 +- .../SolutionIntegrationTests.cs | 2 +- .../SLNX-validator.Tests/ValidatorRunnerTests.cs | 2 +- 6 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 src/SLNX-validator.Core/Validation/SlnxXsdProvider.cs diff --git a/src/SLNX-validator.Core/ServiceCollectionExtensions.cs b/src/SLNX-validator.Core/ServiceCollectionExtensions.cs index 000c08c..28ccf8a 100644 --- a/src/SLNX-validator.Core/ServiceCollectionExtensions.cs +++ b/src/SLNX-validator.Core/ServiceCollectionExtensions.cs @@ -11,6 +11,7 @@ public static IServiceCollection AddSlnxValidator(this IServiceCollection servic { services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/SLNX-validator.Core/Validation/SlnxXsdProvider.cs b/src/SLNX-validator.Core/Validation/SlnxXsdProvider.cs new file mode 100644 index 0000000..592e226 --- /dev/null +++ b/src/SLNX-validator.Core/Validation/SlnxXsdProvider.cs @@ -0,0 +1,16 @@ +using System.Reflection; + +namespace JulianVerdurmen.SlnxValidator.Core.Validation; + +public sealed class SlnxXsdProvider +{ + // Source: https://github.com/microsoft/vs-solutionpersistence/blob/main/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/Slnx.xsd + private const string XsdResourceName = "JulianVerdurmen.SlnxValidator.Slnx.xsd"; + + public Stream GetXsdStream() + { + return Assembly + .GetExecutingAssembly() + .GetManifestResourceStream(XsdResourceName) ?? throw new InvalidOperationException($"XSD resource '{XsdResourceName}' not found in assembly"); + } +} diff --git a/src/SLNX-validator.Core/Validation/XsdValidator.cs b/src/SLNX-validator.Core/Validation/XsdValidator.cs index f57e9cb..20d85b7 100644 --- a/src/SLNX-validator.Core/Validation/XsdValidator.cs +++ b/src/SLNX-validator.Core/Validation/XsdValidator.cs @@ -1,22 +1,16 @@ -using System.Reflection; using System.Xml; using System.Xml.Schema; using JulianVerdurmen.SlnxValidator.Core.ValidationResults; namespace JulianVerdurmen.SlnxValidator.Core.Validation; -public sealed class XsdValidator : IXsdValidator +public sealed class XsdValidator(SlnxXsdProvider xsdProvider) : IXsdValidator { - // Source: https://github.com/microsoft/vs-solutionpersistence/blob/main/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/Slnx.xsd - private const string XsdResourceName = "JulianVerdurmen.SlnxValidator.Slnx.xsd"; - public async Task ValidateAsync(string slnxContent, ValidationResult result, CancellationToken cancellationToken) { var schemas = new XmlSchemaSet(); - await using var xsdStream = Assembly - .GetExecutingAssembly() - .GetManifestResourceStream(XsdResourceName) ?? throw new InvalidOperationException("XSD file not found"); + await using var xsdStream = xsdProvider.GetXsdStream(); using var xsdReader = XmlReader.Create(xsdStream); schemas.Add(null, xsdReader); diff --git a/tests/SLNX-validator.Core.Tests/SlnxValidatorTests.cs b/tests/SLNX-validator.Core.Tests/SlnxValidatorTests.cs index 4f4ac46..30013a7 100644 --- a/tests/SLNX-validator.Core.Tests/SlnxValidatorTests.cs +++ b/tests/SLNX-validator.Core.Tests/SlnxValidatorTests.cs @@ -7,7 +7,7 @@ namespace JulianVerdurmen.SlnxValidator.Core.Tests; public class SlnxValidatorTests { private static Validation.SlnxValidator ValidatorWithFiles(params string[] existingPaths) - => new(new MockFileSystem(existingPaths), new XsdValidator()); + => new(new MockFileSystem(existingPaths), new XsdValidator(new SlnxXsdProvider())); private static readonly string RepoRoot = OperatingSystem.IsWindows() ? @"C:\repo" : "/repo"; diff --git a/tests/SLNX-validator.Core.Tests/SolutionIntegrationTests.cs b/tests/SLNX-validator.Core.Tests/SolutionIntegrationTests.cs index 9280404..6eb2f04 100644 --- a/tests/SLNX-validator.Core.Tests/SolutionIntegrationTests.cs +++ b/tests/SLNX-validator.Core.Tests/SolutionIntegrationTests.cs @@ -21,7 +21,7 @@ public async Task OwnSlnxFile_HasNoValidationErrors() var slnxFile = directory!.EnumerateFiles("*.slnx").First(); var content = await File.ReadAllTextAsync(slnxFile.FullName); - var validator = new CoreSlnxValidator(new RealFileSystem(), new XsdValidator()); + var validator = new CoreSlnxValidator(new RealFileSystem(), new XsdValidator(new SlnxXsdProvider())); var result = await validator.ValidateAsync(content, slnxFile.DirectoryName!); result.Errors.Should().BeEmpty(); diff --git a/tests/SLNX-validator.Tests/ValidatorRunnerTests.cs b/tests/SLNX-validator.Tests/ValidatorRunnerTests.cs index c486b54..1c45d43 100644 --- a/tests/SLNX-validator.Tests/ValidatorRunnerTests.cs +++ b/tests/SLNX-validator.Tests/ValidatorRunnerTests.cs @@ -11,7 +11,7 @@ public class ValidatorRunnerTests private static ValidatorRunner CreateRunner(IFileSystem fileSystem) { var resolver = new SlnxFileResolver(fileSystem); - var validator = new CoreSlnxValidator(fileSystem, new XsdValidator()); + var validator = new CoreSlnxValidator(fileSystem, new XsdValidator(new SlnxXsdProvider())); var collector = new ValidationCollector(fileSystem, validator); var sonarReporter = new SonarReporter(fileSystem); return new ValidatorRunner(resolver, collector, sonarReporter); From e08b310e3c00b465fdd76363c5ee1d72acfce5a2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 12 Mar 2026 09:30:46 +0000 Subject: [PATCH 3/3] Add ISlnxXsdProvider interface and use it in XsdValidator and DI registration Co-authored-by: 304NotModified <5808377+304NotModified@users.noreply.github.com> --- src/SLNX-validator.Core/ServiceCollectionExtensions.cs | 2 +- src/SLNX-validator.Core/Validation/ISlnxXsdProvider.cs | 6 ++++++ src/SLNX-validator.Core/Validation/SlnxXsdProvider.cs | 2 +- src/SLNX-validator.Core/Validation/XsdValidator.cs | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 src/SLNX-validator.Core/Validation/ISlnxXsdProvider.cs diff --git a/src/SLNX-validator.Core/ServiceCollectionExtensions.cs b/src/SLNX-validator.Core/ServiceCollectionExtensions.cs index 28ccf8a..1e1a29d 100644 --- a/src/SLNX-validator.Core/ServiceCollectionExtensions.cs +++ b/src/SLNX-validator.Core/ServiceCollectionExtensions.cs @@ -11,7 +11,7 @@ public static IServiceCollection AddSlnxValidator(this IServiceCollection servic { services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/SLNX-validator.Core/Validation/ISlnxXsdProvider.cs b/src/SLNX-validator.Core/Validation/ISlnxXsdProvider.cs new file mode 100644 index 0000000..dcfe58c --- /dev/null +++ b/src/SLNX-validator.Core/Validation/ISlnxXsdProvider.cs @@ -0,0 +1,6 @@ +namespace JulianVerdurmen.SlnxValidator.Core.Validation; + +public interface ISlnxXsdProvider +{ + Stream GetXsdStream(); +} diff --git a/src/SLNX-validator.Core/Validation/SlnxXsdProvider.cs b/src/SLNX-validator.Core/Validation/SlnxXsdProvider.cs index 592e226..c68eaba 100644 --- a/src/SLNX-validator.Core/Validation/SlnxXsdProvider.cs +++ b/src/SLNX-validator.Core/Validation/SlnxXsdProvider.cs @@ -2,7 +2,7 @@ namespace JulianVerdurmen.SlnxValidator.Core.Validation; -public sealed class SlnxXsdProvider +public sealed class SlnxXsdProvider : ISlnxXsdProvider { // Source: https://github.com/microsoft/vs-solutionpersistence/blob/main/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/Slnx.xsd private const string XsdResourceName = "JulianVerdurmen.SlnxValidator.Slnx.xsd"; diff --git a/src/SLNX-validator.Core/Validation/XsdValidator.cs b/src/SLNX-validator.Core/Validation/XsdValidator.cs index 20d85b7..eb46a2d 100644 --- a/src/SLNX-validator.Core/Validation/XsdValidator.cs +++ b/src/SLNX-validator.Core/Validation/XsdValidator.cs @@ -4,7 +4,7 @@ namespace JulianVerdurmen.SlnxValidator.Core.Validation; -public sealed class XsdValidator(SlnxXsdProvider xsdProvider) : IXsdValidator +public sealed class XsdValidator(ISlnxXsdProvider xsdProvider) : IXsdValidator { public async Task ValidateAsync(string slnxContent, ValidationResult result, CancellationToken cancellationToken) {