diff --git a/README.md b/README.md index a7f9b19..e56889f 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,10 @@ The target type lets MergePatchDto generate typed mapping: patch.ApplyTo(person); ``` +If the same patch shape should apply to multiple concrete types, target a +shared interface. Generated `ApplyTo` accepts the interface and maps only +members declared on that interface. + It does not mean every property on `Person` is patchable. The DTO remains the boundary. ## Manual Updates @@ -174,9 +178,7 @@ If a target property should not be patchable, leave it off the DTO. deserialized and presence-tracked, but excluded from generated `ApplyTo`. - `[PatchUsing(nameof(Method))]` calls custom domain logic when the patch property was provided. -- `[MergePatchTarget(typeof(OtherTarget))]` adds another typed `ApplyTo` - overload. -- Targets can be interfaces. In that case, generated `ApplyTo` accepts the interface and maps only members declared on that interface. +- Targets can be interfaces. ```csharp [MergePatch(typeof(Person))] diff --git a/src/MergePatchDto.Generators/MergePatchGenerator.cs b/src/MergePatchDto.Generators/MergePatchGenerator.cs index 32accca..cef16aa 100644 --- a/src/MergePatchDto.Generators/MergePatchGenerator.cs +++ b/src/MergePatchDto.Generators/MergePatchGenerator.cs @@ -12,7 +12,6 @@ namespace MergePatchDto.Generators public sealed class MergePatchGenerator : IIncrementalGenerator { private const string MergePatchAttributeName = "MergePatch.MergePatchAttribute"; - private const string MergePatchTargetAttributeName = "MergePatch.MergePatchTargetAttribute"; private const string PatchIgnoreAttributeName = "MergePatch.PatchIgnoreAttribute"; private const string PatchToAttributeName = "MergePatch.PatchToAttribute"; private const string PatchUsingAttributeName = "MergePatch.PatchUsingAttribute"; @@ -382,14 +381,9 @@ private static EffectiveVisibility Min(EffectiveVisibility left, EffectiveVisibi var patchDtoAttribute = context.Attributes.FirstOrDefault(attribute => IsAttribute(attribute, MergePatchAttributeName)); - var targetAttributes = typeSymbol - .GetAttributes() - .Where(attribute => IsAttribute(attribute, MergePatchTargetAttributeName)) - .ToArray(); - - var targetDeclarations = targetAttributes - .Concat(patchDtoAttribute == null ? Enumerable.Empty() : new[] { patchDtoAttribute }) - .ToArray(); + var targetDeclarations = patchDtoAttribute == null + ? Enumerable.Empty() + : new[] { patchDtoAttribute }; var targets = targetDeclarations .Select(BuildTargetModel) diff --git a/src/MergePatchDto/MergePatchTargetAttribute.cs b/src/MergePatchDto/MergePatchTargetAttribute.cs deleted file mode 100644 index d0d6d20..0000000 --- a/src/MergePatchDto/MergePatchTargetAttribute.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; - -namespace MergePatch -{ - /// - /// Adds an additional target type for a merge-patch DTO. - /// - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - public sealed class MergePatchTargetAttribute : Attribute - { - /// - /// Initializes a merge-patch target declaration for the specified type. - /// - /// The additional type that receives generated apply methods. - public MergePatchTargetAttribute(Type targetType) - { - TargetType = targetType; - } - - /// - /// Gets the additional target type for generated apply methods. - /// - public Type TargetType { get; } - } -} diff --git a/tests/MergePatchDto.Tests/ApplyToConventionTests.cs b/tests/MergePatchDto.Tests/ApplyToConventionTests.cs index 4107898..04fefc9 100644 --- a/tests/MergePatchDto.Tests/ApplyToConventionTests.cs +++ b/tests/MergePatchDto.Tests/ApplyToConventionTests.cs @@ -40,20 +40,6 @@ public void ApplyToDoesNotCallSetterForMissingProperty() Assert.Equal(before, target.NameSetCount); } - [Fact] - public void PatchDtoCanGenerateMultipleTargetOverloads() - { - var patch = JsonSerializer.Deserialize("""{ "Name": "Draft" }""")!; - var documentTarget = new Document(); - var draftTarget = new DocumentDraft(); - - patch.ApplyTo(documentTarget); - patch.ApplyTo(draftTarget); - - Assert.Equal("Draft", documentTarget.Name); - Assert.Equal("Draft", draftTarget.Name); - } - [Fact] public void PatchDtoCanTargetInterfaceImplementedByMultipleClasses() { diff --git a/tests/MergePatchDto.Tests/DiagnosticsTests.cs b/tests/MergePatchDto.Tests/DiagnosticsTests.cs index 55feaa5..59bb5e4 100644 --- a/tests/MergePatchDto.Tests/DiagnosticsTests.cs +++ b/tests/MergePatchDto.Tests/DiagnosticsTests.cs @@ -96,8 +96,7 @@ public void ReportsErrorWhenPatchTargetCannotBeResolved() """ using MergePatch; - [MergePatch] - [MergePatchTarget(typeof(MissingTarget))] + [MergePatch(typeof(MissingTarget))] public partial class Patch { public string? Name { get; set; } @@ -132,32 +131,6 @@ public partial class Patch !diagnostic.Id.StartsWith("MPD", StringComparison.Ordinal)); } - [Fact] - public void ReportsErrorWhenAdditionalPatchTargetIsOpenGeneric() - { - var diagnostics = DiagnosticTestHelper.GetAllDiagnostics( - """ - using MergePatch; - - public class Box - { - public string? Name { get; set; } - } - - [MergePatch] - [MergePatchTarget(typeof(Box<>))] - public partial class Patch - { - public string? Name { get; set; } - } - """); - - Assert.Contains(diagnostics, diagnostic => diagnostic.Id == "MPD018" && diagnostic.Severity == DiagnosticSeverity.Error); - Assert.DoesNotContain(diagnostics, diagnostic => - diagnostic.Severity == DiagnosticSeverity.Error && - !diagnostic.Id.StartsWith("MPD", StringComparison.Ordinal)); - } - [Fact] public void ReportsErrorWhenPatchTargetIsLessAccessibleThanPublicPatchDto() { diff --git a/tests/MergePatchDto.Tests/TestModels.cs b/tests/MergePatchDto.Tests/TestModels.cs index 29f0806..1278702 100644 --- a/tests/MergePatchDto.Tests/TestModels.cs +++ b/tests/MergePatchDto.Tests/TestModels.cs @@ -71,11 +71,6 @@ public void SetPriority(int? value) } } -public sealed class DocumentDraft -{ - public string? Name { get; set; } -} - public interface INamedResource { string? Name { get; set; } @@ -120,14 +115,6 @@ private static void ApplyPriority(Document target, int? value) } } -[MergePatch] -[MergePatchTarget(typeof(Document))] -[MergePatchTarget(typeof(DocumentDraft))] -public partial class MultiTargetPatch -{ - public string? Name { get; set; } -} - [MergePatch(typeof(INamedResource))] public partial class InterfaceTargetPatch {