diff --git a/.github/workflows/buildandtest.yml b/.github/workflows/buildandtest.yml deleted file mode 100644 index 659168f..0000000 --- a/.github/workflows/buildandtest.yml +++ /dev/null @@ -1,25 +0,0 @@ -name: .NET - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: Setup .NET - uses: actions/setup-dotnet@v1 - with: - dotnet-version: 5.0.x - - name: Restore dependencies - run: dotnet restore - - name: Build - run: dotnet build --no-restore - - name: Test - run: dotnet test --no-build --verbosity normal diff --git a/ProtoAttributor.Tests/DataContracts/AttributeReaderTests.cs b/ProtoAttributor.Tests/DataContracts/AttributeReaderTests.cs new file mode 100644 index 0000000..c3d4567 --- /dev/null +++ b/ProtoAttributor.Tests/DataContracts/AttributeReaderTests.cs @@ -0,0 +1,27 @@ +using System.IO; +using FluentAssertions; +using Microsoft.CodeAnalysis.CSharp; +using ProtoAttributor.Parsers.DataContracts; +using Xunit; + +namespace ProtoAttributor.Tests.DataContracts +{ + public class AttributeReaderTests + { + public string LoadTestFile(string relativePath) + { + return File.ReadAllText(relativePath); + } + + [Fact] + public void GetsNextIdForDataMember() + { + var tree = CSharpSyntaxTree.ParseText(LoadTestFile(@"./Mocks/TestCodeWithDataMemberAttributes.cs")); + var protoReader = new DataAttributeReader(); + + var output = protoReader.GetDataMemberNextId(tree.GetRoot()); + + output.Should().Be(3); + } + } +} diff --git a/ProtoAttributor.Tests/DataContracts/DataAttributeAdderTests.cs b/ProtoAttributor.Tests/DataContracts/DataAttributeAdderTests.cs new file mode 100644 index 0000000..dee0f2b --- /dev/null +++ b/ProtoAttributor.Tests/DataContracts/DataAttributeAdderTests.cs @@ -0,0 +1,158 @@ +using System; +using FluentAssertions; +using Microsoft.CodeAnalysis.CSharp; +using ProtoAttributor.Parsers.DataContracts; +using Xunit; + +namespace ProtoAttributor.Tests.DataContracts +{ + public class DataAttributeAdderTests: IClassFixture + { + private readonly TestFixure _fixture; + + public DataAttributeAdderTests(TestFixure fixture) + { + _fixture = fixture; + } + + [Fact] + public void AddsAttributesForProtoBuf() + { + var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestClassPlain.cs")); + var rewriter = new DataAttributeAdder(); + + var rewrittenRoot = rewriter.Visit(tree.GetRoot()); + + var output = rewrittenRoot.GetText().ToString(); + + var source = output.Split(new string[] { " ", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + + output.Should().Contain("System.Runtime.Serialization"); + output.Should().Contain("[DataContract]"); + output.Should().Contain("[Required]"); + output.Should().Contain("[DataMember(Order = 1)]"); + output.Should().Contain("[DataMember(Order = 2)]"); + + _fixture.AssertOutputContainsCount(source, "DataMember", 2); + _fixture.AssertOutputContainsCount(source, "Required", 1); + } + + [Fact] + public void AddsAttributesForProtBufWherePropDontHaveIgnoreDataMember() + { + var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestCodeWithAttributesAndDataMemberIgnore.cs")); + var rewriter = new DataAttributeAdder(); + var rewrittenRoot = rewriter.Visit(tree.GetRoot()); + + var output = rewrittenRoot.GetText().ToString(); + + var source = output.Split(new string[] { " ", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + + output.Should().Contain("System.Runtime.Serialization"); + output.Should().Contain("[DataContract]"); + output.Should().Contain("[Required]"); + output.Should().Contain("[DataMember(Order = 1)]"); + output.Should().Contain("[DataMember(Order = 2)]"); + output.Should().Contain("[DataMember(Order = 3)]"); + + _fixture.AssertOutputContainsCount(source, "[DataMember", 3); + _fixture.AssertOutputContainsCount(source, "[Required]", 1); + _fixture.AssertOutputContainsCount(source, "[IgnoreDataMember]", 1); + } + + [Fact] + public void AddsAttributesAndKeepCommentsInTack() + { + var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestClassWithXmlComments.cs")); + var rewriter = new DataAttributeAdder(); + + var rewrittenRoot = rewriter.Visit(tree.GetRoot()); + + var output = rewrittenRoot.GetText().ToString(); + + output.Should().Contain("System.Runtime.Serialization"); + output.Should().Contain("[DataContract]"); + output.Should().Contain("[DataMember(Order = 1)]"); + output.Should().Contain("[DataMember(Order = 2)]"); + + output.Should().Contain(" /// "); + output.Should().Contain(" [DataMember(Order = 1)]"); + output.Should().Contain(" public int MyProperty { get; set; }"); + + //This verifies spacing is correct + output.Should().Contain(@" + /// Comments not wrapped + /// My property. + [DataMember(Order = 1)] + public int MyProperty { get; set; }"); + } + + [Fact] + public void AddsUsingWhenNoneExist() + { + var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestClassNoUsings.cs")); + var rewriter = new DataAttributeAdder(); + + var rewrittenRoot = rewriter.Visit(tree.GetRoot()); + + var output = rewrittenRoot.GetText().ToString(); + + output.Should().Contain("System.Runtime.Serialization"); + output.Should().Contain("[DataContract]"); + output.Should().Contain("[DataMember(Order = 1)]"); + output.Should().Contain("[DataMember(Order = 2)]"); + } + + [Fact] + public void AddsAttributesWithCorrectOrderWhenAttributesAlreadyExists() + { + var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestCodeWithDataMemberAttributes.cs")); + var rewriter = new DataAttributeAdder(); + + var rewrittenRoot = rewriter.Visit(tree.GetRoot()); + + var output = rewrittenRoot.GetText().ToString(); + + output.Should().Contain("System.Runtime.Serialization"); + output.Should().Contain("[DataContract]"); + output.Should().Contain("[DataMember(Order = 1)]"); + output.Should().Contain("[DataMember(Order = 2)]"); + output.Should().Contain("[DataMember(Order = 3)]"); + output.Should().Contain("[DataMember(Name = \"Test\")]"); + } + + [Fact] + public void AddsAttributesWithCorrectOrderWhenFileHasWierdFormatting() + { + var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestWierdFormatting.cs")); + var rewriter = new DataAttributeAdder(); + var rewrittenRoot = rewriter.Visit(tree.GetRoot()); + + var output = rewrittenRoot.GetText().ToString(); + + output.Should().Contain("System.Runtime.Serialization"); + output.Should().Contain("[DataContract]"); + output.Should().Contain("[DataMember(Order = 1)]"); + output.Should().Contain("[DataMember(Order = 2)]"); + } + + [Fact] + public void AddsAttributesWithCorrectOrderWhenFileHasProtoIgnores() + { + var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestIgnoreDataMember.cs")); + var rewriter = new DataAttributeAdder(); + var rewrittenRoot = rewriter.Visit(tree.GetRoot()); + + var output = rewrittenRoot.GetText().ToString(); + var source = output.Split(new string[] { " ", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + + output.Should().Contain("System.Runtime.Serialization"); + output.Should().Contain("[DataContract]"); + output.Should().Contain("[DataMember(Order = 1)]"); + output.Should().Contain("[DataMember(Order = 2)]"); + output.Should().Contain("[DataMember(Order = 14)]"); + output.Should().Contain("[DataMember(Order = 16)]"); + _fixture.AssertOutputContainsCount(source, "[IgnoreDataMember]", 2); + } + } +} diff --git a/ProtoAttributor.Tests/DataContracts/DataAttributeRemoverTests.cs b/ProtoAttributor.Tests/DataContracts/DataAttributeRemoverTests.cs new file mode 100644 index 0000000..be44829 --- /dev/null +++ b/ProtoAttributor.Tests/DataContracts/DataAttributeRemoverTests.cs @@ -0,0 +1,40 @@ +using FluentAssertions; +using Microsoft.CodeAnalysis.CSharp; +using ProtoAttributor.Parsers.DataContracts; +using Xunit; + +namespace ProtoAttributor.Tests.DataContracts +{ + public class DataAttributeRemoverTests: IClassFixture + { + private readonly TestFixure _fixture; + + public DataAttributeRemoverTests(TestFixure fixture) + { + _fixture = fixture; + } + + [Fact] + public void AddsAttributesWithCorrectOrderWhenAttributesAlreadyExists() + { + var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestRemoveDataAttributes.cs")); + var rewriter = new DataAttributeRemover(); + + var rewrittenRoot = rewriter.Visit(tree.GetRoot()); + + var output = rewrittenRoot.GetText().ToString(); + + output.Should().NotContain("System.Runtime.Serialization"); + output.Should().NotContain("[DataContract]"); + output.Should().NotContain("[KnownType"); + output.Should().NotContain("[IgnoreDataMember]"); + output.Should().NotContain(@"[DataMember(Order = 1, Name=""Test"")]"); + output.Should().NotContain("[DataMember(Order = 2)]"); + output.Should().NotContain(@"DataMember(Name = ""test12"")"); + + output.Should().Contain("[Required]"); + + output.Should().Contain("[Serializable]"); + } + } +} diff --git a/ProtoAttributor.Tests/DataContracts/DataAttributeRewriterTests.cs b/ProtoAttributor.Tests/DataContracts/DataAttributeRewriterTests.cs new file mode 100644 index 0000000..3b22959 --- /dev/null +++ b/ProtoAttributor.Tests/DataContracts/DataAttributeRewriterTests.cs @@ -0,0 +1,95 @@ +using System; +using FluentAssertions; +using Microsoft.CodeAnalysis.CSharp; +using ProtoAttributor.Parsers.DataContracts; +using Xunit; + +namespace ProtoAttributor.Tests.DataContracts +{ + public class DataAttributeRewriterTests: IClassFixture + { + private readonly TestFixure _fixture; + + public DataAttributeRewriterTests(TestFixure fixture) + { + _fixture = fixture; + } + + private readonly string _codeWithAttributes = @" + using System; + using Xunit; + namespace ProtoAttributor.Tests + { + [Required] + public class Test + { + [Required] + [DataMember(Order = 10, Name=""Test"")] + public int MyProperty { get; set; } + [DataMember(Order = 20)] + public int MyProperty2 { get; set; } + + [Required] + public int MyProperty3 { get; set; } + public int MyProperty4 { get; set; } + } + } + "; + + [Fact] + public void RewritesAttributesWithCorrectOrderWhenAttributesAlreadyExists() + { + var tree = CSharpSyntaxTree.ParseText(_codeWithAttributes); + var rewriter = new DataAttributeRewriter(); + + var rewrittenRoot = rewriter.Visit(tree.GetRoot()); + + var output = rewrittenRoot.GetText().ToString(); + + output.Should().Contain("System.Runtime.Serialization"); + output.Should().Contain("[DataContract]"); + output.Should().Contain(@"[DataMember(Order = 1, Name=""Test"")]"); + output.Should().Contain("[DataMember(Order = 2)]"); + output.Should().Contain("[DataMember(Order = 3)]"); + output.Should().Contain("[DataMember(Order = 4)]"); + } + + [Fact] + public void RewritesAttributesWithCorrectOrderWhenFileHasProtoIgnores() + { + var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestDataIgnore.cs")); + var rewriter = new DataAttributeRewriter(); + var rewrittenRoot = rewriter.Visit(tree.GetRoot()); + + var output = rewrittenRoot.GetText().ToString(); + var source = output.Split(new string[] { " ", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + + output.Should().Contain("System.Runtime.Serialization"); + output.Should().Contain("[DataContract]"); + output.Should().Contain("[DataMember(Order = 1)]"); + output.Should().Contain("[DataMember(Order = 2)]"); + output.Should().Contain("[DataMember(Order = 3)]"); + output.Should().Contain("[DataMember(Order = 4)]"); + _fixture.AssertOutputContainsCount(source, "[IgnoreDataMember]", 2); + } + + [Fact] + public void RewritesAttributesWithCorrectOrderWhenAttributeExistsWithoutOrderProperty() + { + var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestMissingOrderPropertyAndWeirdSpacing.cs")); + var rewriter = new DataAttributeRewriter(); + var rewrittenRoot = rewriter.Visit(tree.GetRoot()); + + var output = rewrittenRoot.GetText().ToString(); + var source = output.Split(new string[] { " ", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + + output.Should().Contain("System.Runtime.Serialization"); + output.Should().Contain("[DataContract]"); + output.Should().Contain("[DataMember(Order = 1)]"); + output.Should().Contain("[DataMember(Order = 2)]"); + output.Should().Contain(@"[DataMember(Name =""test"",Order = 3)]"); + output.Should().Contain("[DataMember(Order = 4)]"); + _fixture.AssertOutputContainsCount(source, "[IgnoreDataMember]", 1); + } + } +} diff --git a/ProtoAttributor.Tests/Mocks/TestClassNoUsings.cs b/ProtoAttributor.Tests/Mocks/TestClassNoUsings.cs index c621dac..f12495d 100644 --- a/ProtoAttributor.Tests/Mocks/TestClassNoUsings.cs +++ b/ProtoAttributor.Tests/Mocks/TestClassNoUsings.cs @@ -1,26 +1,14 @@ - namespace ProtoAttributor.Tests.Mocks { - /// - /// TestClass - /// + /// TestClass public class TestClassWithNoUsings { - /// - /// Gets or sets my property. - /// - /// - /// My property. - /// + /// Gets or sets my property. + /// My property. public int MyProperty { get; set; } - /// - /// Gets or sets my property11. - /// - /// - /// My property11. - /// + /// Gets or sets my property11. + /// My property11. public int MyProperty11 { get; set; } - } } diff --git a/ProtoAttributor.Tests/Mocks/TestClassPlain.cs b/ProtoAttributor.Tests/Mocks/TestClassPlain.cs index 377abe9..1cff18e 100644 --- a/ProtoAttributor.Tests/Mocks/TestClassPlain.cs +++ b/ProtoAttributor.Tests/Mocks/TestClassPlain.cs @@ -1,8 +1,4 @@ -using FluentAssertions; -using Microsoft.CodeAnalysis.CSharp; using System.ComponentModel.DataAnnotations; -using System; -using Xunit; namespace ProtoAttributor.Tests.Mocks { @@ -10,6 +6,7 @@ public class TestClassPlain { [Required] public int MyProperty { get; set; } + public int MyProperty2 { get; set; } } } diff --git a/ProtoAttributor.Tests/Mocks/TestClassWithXmlComments.cs b/ProtoAttributor.Tests/Mocks/TestClassWithXmlComments.cs index 832df1e..ec81400 100644 --- a/ProtoAttributor.Tests/Mocks/TestClassWithXmlComments.cs +++ b/ProtoAttributor.Tests/Mocks/TestClassWithXmlComments.cs @@ -1,8 +1,3 @@ -using FluentAssertions; -using Microsoft.CodeAnalysis.CSharp; -using System; -using Xunit; - namespace ProtoAttributor.Tests.Mocks { /// @@ -10,12 +5,8 @@ namespace ProtoAttributor.Tests.Mocks /// public class TestClassWithXmlComments { - /// - /// Gets or sets my property. - /// - /// - /// My property. - /// + /// Comments not wrapped + /// My property. public int MyProperty { get; set; } /// @@ -25,6 +16,5 @@ public class TestClassWithXmlComments /// My property11. /// public int MyProperty11 { get; set; } - } } diff --git a/ProtoAttributor.Tests/Mocks/TestCodeWithAttributesAndDataMemberIgnore.cs b/ProtoAttributor.Tests/Mocks/TestCodeWithAttributesAndDataMemberIgnore.cs new file mode 100644 index 0000000..1d827c4 --- /dev/null +++ b/ProtoAttributor.Tests/Mocks/TestCodeWithAttributesAndDataMemberIgnore.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; + +namespace ProtoAttributor.Tests +{ + [DataContract] + public class TestCodeWithAttributesAndDataMemberIgnore + { + [Required] + [DataMember(Order = 1)] + public int MyProperty { get; set; } + + [DataMember(Order = 2)] + public int MyProperty2 { get; set; } + + [IgnoreDataMember] + public int MyProperty3 { get; set; } + + public int MyProperty4 { get; set; } + } +} diff --git a/ProtoAttributor.Tests/Mocks/TestCodeWithAttributesAndProtoIgnore.cs b/ProtoAttributor.Tests/Mocks/TestCodeWithAttributesAndProtoIgnore.cs index 9694555..4fea9cd 100644 --- a/ProtoAttributor.Tests/Mocks/TestCodeWithAttributesAndProtoIgnore.cs +++ b/ProtoAttributor.Tests/Mocks/TestCodeWithAttributesAndProtoIgnore.cs @@ -1,21 +1,21 @@ -using System; -using Xunit; -using ProtoBuf; using System.ComponentModel.DataAnnotations; +using ProtoBuf; namespace ProtoAttributor.Tests { - [ProtoContract] public class TestCodeWithAttributesAndProtoIgnore { [Required] [ProtoMember(1)] public int MyProperty { get; set; } + [ProtoMember(2)] public int MyProperty2 { get; set; } + [ProtoIgnore] public int MyProperty3 { get; set; } + public int MyProperty4 { get; set; } } } diff --git a/ProtoAttributor.Tests/Mocks/TestCodeWithDataMemberAttributes.cs b/ProtoAttributor.Tests/Mocks/TestCodeWithDataMemberAttributes.cs new file mode 100644 index 0000000..667a0ce --- /dev/null +++ b/ProtoAttributor.Tests/Mocks/TestCodeWithDataMemberAttributes.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; + +namespace ProtoAttributor.Tests +{ + [DataContract] + public class TestCodeWithDataMemberAttributes + { + [Required] + [DataMember(Order = 1)] + public int MyProperty { get; set; } + + [DataMember(Order = 2)] + public int MyProperty2 { get; set; } + + [DataMember(Name = "Test")] + public int MyProperty3 { get; set; } + + public int MyProperty4 { get; set; } + } +} diff --git a/ProtoAttributor.Tests/Mocks/TestCodeWithAttributes.cs b/ProtoAttributor.Tests/Mocks/TestCodeWithProtoAttributes.cs similarity index 81% rename from ProtoAttributor.Tests/Mocks/TestCodeWithAttributes.cs rename to ProtoAttributor.Tests/Mocks/TestCodeWithProtoAttributes.cs index 476137d..ad05f7f 100644 --- a/ProtoAttributor.Tests/Mocks/TestCodeWithAttributes.cs +++ b/ProtoAttributor.Tests/Mocks/TestCodeWithProtoAttributes.cs @@ -1,19 +1,20 @@ -using System; -using Xunit; -using ProtoBuf; using System.ComponentModel.DataAnnotations; +using ProtoBuf; namespace ProtoAttributor.Tests { [ProtoContract] - public class TestCodeWithAttributes + public class TestCodeWithProtoAttributes { [Required] [ProtoMember(1)] public int MyProperty { get; set; } + [ProtoMember(2)] public int MyProperty2 { get; set; } + public int MyProperty3 { get; set; } + public int MyProperty4 { get; set; } } } diff --git a/ProtoAttributor.Tests/Mocks/TestDataIgnore.cs b/ProtoAttributor.Tests/Mocks/TestDataIgnore.cs new file mode 100644 index 0000000..4b9c4f3 --- /dev/null +++ b/ProtoAttributor.Tests/Mocks/TestDataIgnore.cs @@ -0,0 +1,27 @@ +using System.Runtime.Serialization; + +namespace ProtoAttributor.Tests.Mocks +{ + // Models returned by MeController actions. + [DataContract] + public class TestDataIgnore + { + [DataMember(Order=1)] + public string Hometown { get; set; } + + [DataMember(Order = 2)] + public string Hometown1 { get; set; } + + [DataMember(Order = 14)] + public string Hometown44 { get; set; } + + [IgnoreDataMember] + public string Hometown55 { get; set; } + + [DataMember(Order=16)] + public string Hometown66 { get; set; } + + [IgnoreDataMember] + public string Hometown99 { get; set; } + } +} diff --git a/ProtoAttributor.Tests/Mocks/TestIgnoreDataMember.cs b/ProtoAttributor.Tests/Mocks/TestIgnoreDataMember.cs new file mode 100644 index 0000000..1ba1211 --- /dev/null +++ b/ProtoAttributor.Tests/Mocks/TestIgnoreDataMember.cs @@ -0,0 +1,27 @@ +using System.Runtime.Serialization; + +namespace ProtoAttributor.Tests.Mocks +{ + // Models returned by MeController actions. + [DataContract] + public class TestIgnoreDataMember + { + [DataMember(Order = 1)] + public string Hometown { get; set; } + + [DataMember(Order = 2)] + public string Hometown1 { get; set; } + + [DataMember(Order = 14)] + public string Hometown44 { get; set; } + + [IgnoreDataMember] + public string Hometown55 { get; set; } + + [DataMember(Order = 16)] + public string Hometown66 { get; set; } + + [IgnoreDataMember] + public string Hometown99 { get; set; } + } +} diff --git a/ProtoAttributor.Tests/Mocks/TestMissingOrderPropertyAndWeirdSpacing.cs b/ProtoAttributor.Tests/Mocks/TestMissingOrderPropertyAndWeirdSpacing.cs new file mode 100644 index 0000000..a60c4d7 --- /dev/null +++ b/ProtoAttributor.Tests/Mocks/TestMissingOrderPropertyAndWeirdSpacing.cs @@ -0,0 +1,23 @@ +using System.Runtime.Serialization; + +namespace ProtoAttributor.Tests.Mocks +{ + // Models returned by MeController actions. + [DataContract] + public class TestMissingOrderPropertyAndWeirdSpacing + { + [DataMember(Order=1)] + public string Hometown { get; set; } + [DataMember(Order= 2)] + public string Hometown2 { get; set; } + + [DataMember(Name ="test")] + public string Hometown1 { get; set; } + + [DataMember(Order =14)] + public string Hometown44 { get; set; } + + [IgnoreDataMember] + public string Hometown99 { get; set; } + } +} diff --git a/ProtoAttributor.Tests/Mocks/TestMultiClassMultiAttribute.cs b/ProtoAttributor.Tests/Mocks/TestMultiClassMultiAttribute.cs index 07190d6..924887b 100644 --- a/ProtoAttributor.Tests/Mocks/TestMultiClassMultiAttribute.cs +++ b/ProtoAttributor.Tests/Mocks/TestMultiClassMultiAttribute.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; @@ -23,8 +22,11 @@ public class ExternalLoginListViewModel public class SendCodeViewModel { public string SelectedProvider { get; set; } + public ICollection Providers { get; set; } + public string ReturnUrl { get; set; } + public bool RememberMe { get; set; } } @@ -36,6 +38,7 @@ public class VerifyCodeViewModel [Required] [Display(Name = "Code")] public string Code { get; set; } + public string ReturnUrl { get; set; } [Display(Name = "Remember this browser?")] diff --git a/ProtoAttributor.Tests/Mocks/TestProtoIgnore.cs b/ProtoAttributor.Tests/Mocks/TestProtoIgnore.cs index 9642e0f..3351e0f 100644 --- a/ProtoAttributor.Tests/Mocks/TestProtoIgnore.cs +++ b/ProtoAttributor.Tests/Mocks/TestProtoIgnore.cs @@ -1,33 +1,27 @@ -using FluentAssertions; -using Microsoft.CodeAnalysis.CSharp; -using System.ComponentModel.DataAnnotations; -using System; -using Xunit; using ProtoBuf; namespace ProtoAttributor.Tests.Mocks { + // Models returned by MeController actions. + [ProtoContract] + public class TestProtoIgnore + { + [ProtoMember(1)] + public string Hometown { get; set; } + [ProtoMember(2)] + public string Hometown1 { get; set; } + [ProtoMember(14)] + public string Hometown44 { get; set; } - // Models returned by MeController actions. - [ProtoContract] - public class TestProtoIgnore - { - [ProtoMember(1)] - public string Hometown { get; set; } - [ProtoMember(2)] - public string Hometown1 { get; set; } - [ProtoMember(14)] - public string Hometown44 { get; set; } - [ProtoIgnore] - public string Hometown55 { get; set; } - [ProtoMember(16)] - public string Hometown66 { get; set; } - [ProtoIgnore] - public string Hometown99 { get; set; } + [ProtoIgnore] + public string Hometown55 { get; set; } + [ProtoMember(16)] + public string Hometown66 { get; set; } + [ProtoIgnore] + public string Hometown99 { get; set; } } - } diff --git a/ProtoAttributor.Tests/Mocks/TestRemoveAttributes.cs b/ProtoAttributor.Tests/Mocks/TestRemoveAttributes.cs index a1f2bbf..d3a6f46 100644 --- a/ProtoAttributor.Tests/Mocks/TestRemoveAttributes.cs +++ b/ProtoAttributor.Tests/Mocks/TestRemoveAttributes.cs @@ -1,8 +1,5 @@ -using FluentAssertions; -using Microsoft.CodeAnalysis.CSharp; -using System.ComponentModel.DataAnnotations; using System; -using Xunit; +using System.ComponentModel.DataAnnotations; using ProtoBuf; namespace ProtoAttributor.Tests.Mocks @@ -13,10 +10,10 @@ namespace ProtoAttributor.Tests.Mocks [ProtoInclude(101, typeof(string))] public class TestRemoveAttributes { - [Required] [ProtoMember(10, Name = "test")] public int MyProperty { get; set; } + [ProtoMember(20)] public int MyProperty2 { get; set; } @@ -28,5 +25,4 @@ public class TestRemoveAttributes public int MyProperty5 { get; set; } } - } diff --git a/ProtoAttributor.Tests/Mocks/TestRemoveDataAttributes.cs b/ProtoAttributor.Tests/Mocks/TestRemoveDataAttributes.cs new file mode 100644 index 0000000..82e1bfc --- /dev/null +++ b/ProtoAttributor.Tests/Mocks/TestRemoveDataAttributes.cs @@ -0,0 +1,31 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Runtime.Serialization; + +namespace ProtoAttributor.Tests.Mocks +{ + [Serializable] + [DataContract] + [KnownType(typeof(string))] + [KnownType(typeof(string))] + public class TestRemoveDataAttributes + { + [Required] + [DataMember(Order = 10, Name = "test")] + public int MyProperty { get; set; } + + [DataMember(Order = 20)] + public int MyProperty2 { get; set; } + + [Required] + public int MyProperty3 { get; set; } + + [IgnoreDataMember] + public int MyProperty4 { get; set; } + + public int MyProperty5 { get; set; } + + [DataMember(Name = "test12")] + public int MyProperty6 { get; set; } + } +} diff --git a/ProtoAttributor.Tests/Mocks/TestWierdFormatting.cs b/ProtoAttributor.Tests/Mocks/TestWierdFormatting.cs index f7cbb20..60f642c 100644 --- a/ProtoAttributor.Tests/Mocks/TestWierdFormatting.cs +++ b/ProtoAttributor.Tests/Mocks/TestWierdFormatting.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; using System.Net; using System.Net.Http; using System.Threading; @@ -16,11 +13,11 @@ public ChallengeResult(string loginProvider) } public string LoginProvider { get; set; } + public HttpRequestMessage Request { get; set; } public Task ExecuteAsync(CancellationToken cancellationToken) { - HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized); response.RequestMessage = Request; return Task.FromResult(response); diff --git a/ProtoAttributor.Tests/ProtoAttributor.Tests.csproj b/ProtoAttributor.Tests/ProtoAttributor.Tests.csproj index 2de6800..02e937b 100644 --- a/ProtoAttributor.Tests/ProtoAttributor.Tests.csproj +++ b/ProtoAttributor.Tests/ProtoAttributor.Tests.csproj @@ -27,6 +27,18 @@ + + Always + + + Always + + + Always + + + Always + Always @@ -39,15 +51,21 @@ Always - + Always Always + + Always + Always + + Always + Always diff --git a/ProtoAttributor.Tests/AttributeReaderTests.cs b/ProtoAttributor.Tests/ProtoContracts/AttributeReaderTests.cs similarity index 78% rename from ProtoAttributor.Tests/AttributeReaderTests.cs rename to ProtoAttributor.Tests/ProtoContracts/AttributeReaderTests.cs index b055605..b99550e 100644 --- a/ProtoAttributor.Tests/AttributeReaderTests.cs +++ b/ProtoAttributor.Tests/ProtoContracts/AttributeReaderTests.cs @@ -1,15 +1,13 @@ +using System.IO; using FluentAssertions; using Microsoft.CodeAnalysis.CSharp; -using ProtoAttributor.Services; -using System; -using System.IO; +using ProtoAttributor.Parsers.ProtoContracts; using Xunit; -namespace ProtoAttributor.Tests +namespace ProtoAttributor.Tests.ProtoContracts { public class AttributeReaderTests { - public string LoadTestFile(string relativePath) { return File.ReadAllText(relativePath); @@ -18,7 +16,7 @@ public string LoadTestFile(string relativePath) [Fact] public void GetsNextIdForProtoMember() { - var tree = CSharpSyntaxTree.ParseText(LoadTestFile(@"./Mocks/TestCodeWithAttributes.cs")); + var tree = CSharpSyntaxTree.ParseText(LoadTestFile(@"./Mocks/TestCodeWithProtoAttributes.cs")); var protoReader = new ProtoAttributeReader(); var output = protoReader.GetProtoNextId(tree.GetRoot()); @@ -26,5 +24,4 @@ public void GetsNextIdForProtoMember() output.Should().Be(3); } } - } diff --git a/ProtoAttributor.Tests/ProtoAttributeAdderTests.cs b/ProtoAttributor.Tests/ProtoContracts/ProtoAttributeAdderTests.cs similarity index 89% rename from ProtoAttributor.Tests/ProtoAttributeAdderTests.cs rename to ProtoAttributor.Tests/ProtoContracts/ProtoAttributeAdderTests.cs index f4f9898..4a6b37d 100644 --- a/ProtoAttributor.Tests/ProtoAttributeAdderTests.cs +++ b/ProtoAttributor.Tests/ProtoContracts/ProtoAttributeAdderTests.cs @@ -1,13 +1,10 @@ +using System; using FluentAssertions; using Microsoft.CodeAnalysis.CSharp; -using ProtoAttributor.Services; -using ProtoBuf; -using System; -using System.IO; -using System.Linq; +using ProtoAttributor.Parsers.ProtoContracts; using Xunit; -namespace ProtoAttributor.Tests +namespace ProtoAttributor.Tests.ProtoContracts { public class ProtoAttributeAdderTests: IClassFixture { @@ -17,17 +14,18 @@ public ProtoAttributeAdderTests(TestFixure fixture) { _fixture = fixture; } + [Fact] public void AddsAttributesForProtBuf() { - var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestClassPlain.cs")); + var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestClassPlain.cs")); var rewriter = new ProtoAttributeAdder(); var rewrittenRoot = rewriter.Visit(tree.GetRoot()); var output = rewrittenRoot.GetText().ToString(); - var source = output.Split(new string[] { " " , "\r\n" }, StringSplitOptions.RemoveEmptyEntries); + var source = output.Split(new string[] { " ", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); output.Should().Contain("ProtoBuf"); output.Should().Contain("[ProtoContract]"); @@ -37,7 +35,6 @@ public void AddsAttributesForProtBuf() _fixture.AssertOutputContainsCount(source, "ProtoMember", 2); _fixture.AssertOutputContainsCount(source, "Required", 1); - } [Fact] @@ -61,7 +58,6 @@ public void AddsAttributesForProtBufWherePropDontHaveProtoIgnore() _fixture.AssertOutputContainsCount(source, "[ProtoMember", 3); _fixture.AssertOutputContainsCount(source, "[Required]", 1); _fixture.AssertOutputContainsCount(source, "[ProtoIgnore]", 1); - } [Fact] @@ -85,15 +81,10 @@ public void AddsAttributesAndKeepCommentsInTack() //This verifies spacing is correct output.Should().Contain(@" - /// - /// Gets or sets my property. - /// - /// - /// My property. - /// + /// Comments not wrapped + /// My property. [ProtoMember(1)] public int MyProperty { get; set; }"); - } [Fact] @@ -115,7 +106,7 @@ public void AddsUsingWhenNoneExist() [Fact] public void AddsAttributesWithCorrectOrderWhenAttributesAlreadyExists() { - var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestCodeWithAttributes.cs")); + var tree = CSharpSyntaxTree.ParseText(_fixture.LoadTestFile(@"./Mocks/TestCodeWithProtoAttributes.cs")); var rewriter = new ProtoAttributeAdder(); var rewrittenRoot = rewriter.Visit(tree.GetRoot()); @@ -155,7 +146,6 @@ public void AddsAttributesWithCorrectOrderWhenFileHasProtoIgnores() var output = rewrittenRoot.GetText().ToString(); var source = output.Split(new string[] { " ", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); - output.Should().Contain("ProtoBuf"); output.Should().Contain("[ProtoContract]"); output.Should().Contain("[ProtoMember(1)]"); @@ -165,5 +155,4 @@ public void AddsAttributesWithCorrectOrderWhenFileHasProtoIgnores() _fixture.AssertOutputContainsCount(source, "[ProtoIgnore]", 2); } } - } diff --git a/ProtoAttributor.Tests/ProtoAttributeRemoverTests.cs b/ProtoAttributor.Tests/ProtoContracts/ProtoAttributeRemoverTests.cs similarity index 90% rename from ProtoAttributor.Tests/ProtoAttributeRemoverTests.cs rename to ProtoAttributor.Tests/ProtoContracts/ProtoAttributeRemoverTests.cs index 5295a15..9a63796 100644 --- a/ProtoAttributor.Tests/ProtoAttributeRemoverTests.cs +++ b/ProtoAttributor.Tests/ProtoContracts/ProtoAttributeRemoverTests.cs @@ -1,12 +1,10 @@ using FluentAssertions; using Microsoft.CodeAnalysis.CSharp; -using ProtoAttributor.Services; -using System; +using ProtoAttributor.Parsers.ProtoContracts; using Xunit; -namespace ProtoAttributor.Tests +namespace ProtoAttributor.Tests.ProtoContracts { - public class ProtoAttributeRemoverTests: IClassFixture { private readonly TestFixure _fixture; @@ -16,7 +14,6 @@ public ProtoAttributeRemoverTests(TestFixure fixture) _fixture = fixture; } - [Fact] public void AddsAttributesWithCorrectOrderWhenAttributesAlreadyExists() { @@ -39,5 +36,4 @@ public void AddsAttributesWithCorrectOrderWhenAttributesAlreadyExists() output.Should().Contain("[Serializable]"); } } - } diff --git a/ProtoAttributor.Tests/ProtoAttributeRewriterTests.cs b/ProtoAttributor.Tests/ProtoContracts/ProtoAttributeRewriterTests.cs similarity index 94% rename from ProtoAttributor.Tests/ProtoAttributeRewriterTests.cs rename to ProtoAttributor.Tests/ProtoContracts/ProtoAttributeRewriterTests.cs index b6ca447..27e394c 100644 --- a/ProtoAttributor.Tests/ProtoAttributeRewriterTests.cs +++ b/ProtoAttributor.Tests/ProtoContracts/ProtoAttributeRewriterTests.cs @@ -1,16 +1,13 @@ +using System; using FluentAssertions; using Microsoft.CodeAnalysis.CSharp; -using ProtoAttributor.Services; -using System; +using ProtoAttributor.Parsers.ProtoContracts; using Xunit; -namespace ProtoAttributor.Tests +namespace ProtoAttributor.Tests.ProtoContracts { - - public class ProtoAttributeRewriterTests: IClassFixture { - private readonly TestFixure _fixture; public ProtoAttributeRewriterTests(TestFixure fixture) @@ -39,7 +36,6 @@ public class Test } "; - [Fact] public void RewritesAttributesWithCorrectOrderWhenAttributesAlreadyExists() { @@ -68,7 +64,6 @@ public void RewritesAttributesWithCorrectOrderWhenFileHasProtoIgnores() var output = rewrittenRoot.GetText().ToString(); var source = output.Split(new string[] { " ", "\r\n" }, StringSplitOptions.RemoveEmptyEntries); - output.Should().Contain("ProtoBuf"); output.Should().Contain("[ProtoContract]"); output.Should().Contain("[ProtoMember(1)]"); @@ -77,7 +72,5 @@ public void RewritesAttributesWithCorrectOrderWhenFileHasProtoIgnores() output.Should().Contain("[ProtoMember(4)]"); _fixture.AssertOutputContainsCount(source, "[ProtoIgnore]", 2); } - } - } diff --git a/ProtoAttributor.Tests/TestFixure.cs b/ProtoAttributor.Tests/TestFixure.cs index fd05fb9..a912d69 100644 --- a/ProtoAttributor.Tests/TestFixure.cs +++ b/ProtoAttributor.Tests/TestFixure.cs @@ -1,11 +1,7 @@ -using FluentAssertions; -using Microsoft.CodeAnalysis.CSharp; -using ProtoAttributor.Services; -using ProtoBuf; using System; using System.IO; using System.Linq; -using Xunit; +using FluentAssertions; namespace ProtoAttributor.Tests { @@ -22,9 +18,7 @@ public void AssertOutputContainsCount(string[] source, string searchTerm, int nu where word.IndexOf(searchTerm, StringComparison.InvariantCultureIgnoreCase) > -1 select word; - matchQuery.Count().Should().Be(numOfTimes); } } - } diff --git a/ProtoAttributor/Commands/Context/DataAnnoAddAttrCommand.cs b/ProtoAttributor/Commands/Context/DataAnnoAddAttrCommand.cs index dade8da..cfe95bf 100644 --- a/ProtoAttributor/Commands/Context/DataAnnoAddAttrCommand.cs +++ b/ProtoAttributor/Commands/Context/DataAnnoAddAttrCommand.cs @@ -24,7 +24,7 @@ internal sealed class DataAnnoAddAttrCommand private readonly AsyncPackage _package; private readonly SDTE _sdteService; - private readonly IProtoAttributeService _attributeService; + private readonly IDataAnnoAttributeService _attributeService; private readonly TextSelectionExecutor _textSelectionExecutor; private readonly IVsThreadedWaitDialogFactory _dialogFactory; private readonly SelectedItemCountExecutor _selectedItemCountExecutor; @@ -38,7 +38,7 @@ internal sealed class DataAnnoAddAttrCommand /// Owner package, not null. /// Command service to add command to, not null. private DataAnnoAddAttrCommand(AsyncPackage package, OleMenuCommandService commandService, SDTE SDTEService, - IProtoAttributeService attributeService, TextSelectionExecutor textSelectionExecutor, + IDataAnnoAttributeService attributeService, TextSelectionExecutor textSelectionExecutor, IVsThreadedWaitDialogFactory dialogFactory, SelectedItemCountExecutor selectedItemCountExecutor, AttributeExecutor attributeExecutor) { @@ -79,7 +79,7 @@ public static async Task InitializeAsync(AsyncPackage package) await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); var commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; - var attributeService = await package.GetServiceAsync(typeof(IProtoAttributeService)) as IProtoAttributeService; + var attributeService = await package.GetServiceAsync(typeof(IDataAnnoAttributeService)) as IDataAnnoAttributeService; var dialogFactory = await package.GetServiceAsync(typeof(SVsThreadedWaitDialogFactory)) as IVsThreadedWaitDialogFactory; var SDTE = await package.GetServiceAsync(typeof(SDTE)) as SDTE; var textSelectionExecutor = new TextSelectionExecutor(); diff --git a/ProtoAttributor/Commands/Context/DataAnnoRemoveAttrCommand.cs b/ProtoAttributor/Commands/Context/DataAnnoRemoveAttrCommand.cs index a9eb8f2..659ab85 100644 --- a/ProtoAttributor/Commands/Context/DataAnnoRemoveAttrCommand.cs +++ b/ProtoAttributor/Commands/Context/DataAnnoRemoveAttrCommand.cs @@ -24,7 +24,7 @@ internal sealed class DataAnnoRemoveAttrCommand private readonly AsyncPackage _package; private readonly SDTE _sdteService; - private readonly IProtoAttributeService _attributeService; + private readonly IDataAnnoAttributeService _attributeService; private readonly TextSelectionExecutor _textSelectionExecutor; private readonly IVsThreadedWaitDialogFactory _dialogFactory; private readonly SelectedItemCountExecutor _selectedItemCountExecutor; @@ -38,7 +38,7 @@ internal sealed class DataAnnoRemoveAttrCommand /// Owner package, not null. /// Command service to add command to, not null. private DataAnnoRemoveAttrCommand(AsyncPackage package, OleMenuCommandService commandService, SDTE SDTEService, - IProtoAttributeService attributeService, TextSelectionExecutor textSelectionExecutor, + IDataAnnoAttributeService attributeService, TextSelectionExecutor textSelectionExecutor, IVsThreadedWaitDialogFactory dialogFactory, SelectedItemCountExecutor selectedItemCountExecutor, AttributeExecutor attributeExecutor) { @@ -79,7 +79,7 @@ public static async Task InitializeAsync(AsyncPackage package) await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); var commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; - var attributeService = await package.GetServiceAsync(typeof(IProtoAttributeService)) as IProtoAttributeService; + var attributeService = await package.GetServiceAsync(typeof(IDataAnnoAttributeService)) as IDataAnnoAttributeService; var dialogFactory = await package.GetServiceAsync(typeof(SVsThreadedWaitDialogFactory)) as IVsThreadedWaitDialogFactory; var SDTE = await package.GetServiceAsync(typeof(SDTE)) as SDTE; var textSelectionExecutor = new TextSelectionExecutor(); diff --git a/ProtoAttributor/Commands/Context/DataAnnoRenumberAttrCommand.cs b/ProtoAttributor/Commands/Context/DataAnnoRenumberAttrCommand.cs index 63a326d..06f7a2d 100644 --- a/ProtoAttributor/Commands/Context/DataAnnoRenumberAttrCommand.cs +++ b/ProtoAttributor/Commands/Context/DataAnnoRenumberAttrCommand.cs @@ -24,7 +24,7 @@ internal sealed class DataAnnoRenumberAttrCommand private readonly AsyncPackage _package; private readonly SDTE _sdteService; - private readonly IProtoAttributeService _attributeService; + private readonly IDataAnnoAttributeService _attributeService; private readonly TextSelectionExecutor _textSelectionExecutor; private readonly IVsThreadedWaitDialogFactory _dialogFactory; private readonly SelectedItemCountExecutor _selectedItemCountExecutor; @@ -38,7 +38,7 @@ internal sealed class DataAnnoRenumberAttrCommand /// Owner package, not null. /// Command service to add command to, not null. private DataAnnoRenumberAttrCommand(AsyncPackage package, OleMenuCommandService commandService, SDTE SDTEService, - IProtoAttributeService attributeService, TextSelectionExecutor textSelectionExecutor, + IDataAnnoAttributeService attributeService, TextSelectionExecutor textSelectionExecutor, IVsThreadedWaitDialogFactory dialogFactory, SelectedItemCountExecutor selectedItemCountExecutor, AttributeExecutor attributeExecutor) { @@ -79,7 +79,7 @@ public static async Task InitializeAsync(AsyncPackage package) await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken); var commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService; - var attributeService = await package.GetServiceAsync(typeof(IProtoAttributeService)) as IProtoAttributeService; + var attributeService = await package.GetServiceAsync(typeof(IDataAnnoAttributeService)) as IDataAnnoAttributeService; var dialogFactory = await package.GetServiceAsync(typeof(SVsThreadedWaitDialogFactory)) as IVsThreadedWaitDialogFactory; var SDTE = await package.GetServiceAsync(typeof(SDTE)) as SDTE; var textSelectionExecutor = new TextSelectionExecutor(); diff --git a/ProtoAttributor/Constants.cs b/ProtoAttributor/Constants.cs index 4a27c86..5fb82cd 100644 --- a/ProtoAttributor/Constants.cs +++ b/ProtoAttributor/Constants.cs @@ -10,5 +10,16 @@ public static class Proto public const string USING_STATEMENT = "ProtoBuf"; public const string BASE_PROP_NAME = "Proto"; } + + public static class Data + { + public const string PROPERTY_ATTRIBUTE_NAME = "DataMember"; + public const string PROPERTY_IGNORE_ATTRIBUTE_NAME = "IgnoreDataMember"; + public const string CLASS_ATTRIBUTE_NAME = "DataContract"; + public const string USING_STATEMENT = "System.Runtime.Serialization"; + public const string BASE_PROP_NAME = "Data"; + public const string BASE_PROPIGNORE_NAME = "IgnoreData"; + public const string BASE_KNOWN_TYPE_NAME = "KnownType"; + } } } diff --git a/ProtoAttributor/Parsers/DataContracts/BaseDataRewriter.cs b/ProtoAttributor/Parsers/DataContracts/BaseDataRewriter.cs new file mode 100644 index 0000000..46f37ff --- /dev/null +++ b/ProtoAttributor/Parsers/DataContracts/BaseDataRewriter.cs @@ -0,0 +1,66 @@ +using System; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Formatting; + +namespace ProtoAttributor.Parsers.DataContracts +{ + public abstract class BaseDataRewriter: CSharpSyntaxRewriter + { + internal int _startIndex; + + public abstract int CalculateStartingIndex(SyntaxNode node); + + public SyntaxList BuildAttribute(AttributeSyntax attribute, + SyntaxList attributeLists, + SyntaxTrivia trailingWhitspace) + { + var newAttribute = NodeHelper.BuildAttributeList(attribute); + + newAttribute = (AttributeListSyntax)VisitAttributeList(newAttribute); + + if (attributeLists.Count > 0) + { + //Existing attribute cause the alignment to be off, this is the adjustment + newAttribute = newAttribute.WithLeadingTrivia(trailingWhitspace); + newAttribute = newAttribute.WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed); + } + else + { + newAttribute = newAttribute.WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed, trailingWhitspace); + } + + newAttribute = newAttribute.WithAdditionalAnnotations(Formatter.Annotation); + return attributeLists.Add(newAttribute); + } + + public override SyntaxNode VisitCompilationUnit(CompilationUnitSyntax node) + { + node = NodeHelper.AddUsing(node, Constants.Data.USING_STATEMENT); + return base.VisitCompilationUnit(node); + } + + public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) + { + //each class needs to restat with the + _startIndex = CalculateStartingIndex(node); + var hasMatch = NodeHelper.HasMatch(node.AttributeLists, Constants.Data.CLASS_ATTRIBUTE_NAME); + + if (!hasMatch) + { + var name = SyntaxFactory.ParseName(Constants.Data.CLASS_ATTRIBUTE_NAME); + var attribute = SyntaxFactory.Attribute(name); + + node = TriviaMaintainer.Apply(node, (innerNode, wp) => + { + var newAttributes = BuildAttribute(attribute, innerNode.AttributeLists, wp); + + return innerNode.WithAttributeLists(newAttributes).WithAdditionalAnnotations(Formatter.Annotation); + }); + } + + return base.VisitClassDeclaration(node); + } + } +} diff --git a/ProtoAttributor/Parsers/DataContracts/DataAttributeAdder.cs b/ProtoAttributor/Parsers/DataContracts/DataAttributeAdder.cs new file mode 100644 index 0000000..0b6c157 --- /dev/null +++ b/ProtoAttributor/Parsers/DataContracts/DataAttributeAdder.cs @@ -0,0 +1,43 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Formatting; + +namespace ProtoAttributor.Parsers.DataContracts +{ + public class DataAttributeAdder: BaseDataRewriter + { + private DataAttributeReader _dataReader; + + public DataAttributeAdder() + { + _dataReader = new DataAttributeReader(); + } + public override int CalculateStartingIndex(SyntaxNode node) + { + return _dataReader.GetDataMemberNextId(node); + } + + public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node) + { + var hasMatch = NodeHelper.HasMatch(node.AttributeLists, Constants.Data.PROPERTY_ATTRIBUTE_NAME, Constants.Data.PROPERTY_IGNORE_ATTRIBUTE_NAME); + + if (!hasMatch) + { + var name = SyntaxFactory.ParseName(Constants.Data.PROPERTY_ATTRIBUTE_NAME); + var arguments = SyntaxFactory.ParseAttributeArgumentList($"(Order = {_startIndex})"); + var attribute = SyntaxFactory.Attribute(name, arguments); //DataMember(Order = 1) + + node = TriviaMaintainer.Apply(node, (innerNode, wp) => + { + var newAttributes = BuildAttribute(attribute, innerNode.AttributeLists, wp); + + return innerNode.WithAttributeLists(newAttributes).WithAdditionalAnnotations(Formatter.Annotation); + }); + _startIndex++; + } + + return base.VisitPropertyDeclaration(node); + } + } +} diff --git a/ProtoAttributor/Parsers/DataContracts/DataAttributeReader.cs b/ProtoAttributor/Parsers/DataContracts/DataAttributeReader.cs new file mode 100644 index 0000000..5615545 --- /dev/null +++ b/ProtoAttributor/Parsers/DataContracts/DataAttributeReader.cs @@ -0,0 +1,60 @@ +using System; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace ProtoAttributor.Parsers.DataContracts +{ + public class DataAttributeReader: CSharpSyntaxWalker + { + private int _highestOrder; + + public int GetDataMemberNextId(SyntaxNode node) + { + _highestOrder = 0; + base.Visit(node); + return _highestOrder + 1; + } + + /// + /// Called when the visitor visits a PropertyDeclarationSyntax node. + /// + /// + public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) + { + if (node.AttributeLists.Count > 0) + { + foreach (var attributeList in node.AttributeLists) + { + var attrs = + attributeList + .Attributes + .Where( + attribute => + NodeHelper.AttributeNameMatches(attribute, Constants.Data.PROPERTY_ATTRIBUTE_NAME) + ) + .ToArray(); + + foreach (var item in attrs) + { + var argument = item.ArgumentList.Arguments.FirstOrDefault(f=>f.NameEquals.Name.Identifier.ValueText.Equals("Order")); + if(argument != null && argument.Expression.Kind() == SyntaxKind.NumericLiteralExpression) + { + var tokenValue = argument.Expression.ChildTokens().FirstOrDefault(f => f.Kind() == SyntaxKind.NumericLiteralToken); + if(tokenValue != null) + { + var order = Convert.ToInt32( tokenValue.Value); + if (order > _highestOrder) + { + _highestOrder = order; + } + } + } + } + } + } + base.VisitPropertyDeclaration(node); + } + } +} diff --git a/ProtoAttributor/Parsers/DataContracts/DataAttributeRemover.cs b/ProtoAttributor/Parsers/DataContracts/DataAttributeRemover.cs new file mode 100644 index 0000000..8023899 --- /dev/null +++ b/ProtoAttributor/Parsers/DataContracts/DataAttributeRemover.cs @@ -0,0 +1,77 @@ +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace ProtoAttributor.Parsers.DataContracts +{ + public class DataAttributeRemover: CSharpSyntaxRewriter + { + public DataAttributeRemover() + { + } + + public override SyntaxNode VisitCompilationUnit(CompilationUnitSyntax node) + { + if (node.Usings.Count > 0) + { + var newUsingDirectives = new SyntaxList(); + var nodesToKeep = node.Usings.Where(directive => directive.Name.ToString() != Constants.Data.USING_STATEMENT).ToArray(); + newUsingDirectives = newUsingDirectives.AddRange(nodesToKeep); + var leadTriv = node.GetLeadingTrivia(); + node = node.WithUsings(newUsingDirectives); + node = node.WithLeadingTrivia(leadTriv); + } + + return base.VisitCompilationUnit(node); + } + + public override SyntaxNode VisitClassDeclaration(ClassDeclarationSyntax node) + { + if (node.AttributeLists.Count > 0) + { + var newAttributeLists = new SyntaxList(); + foreach (var attributeList in node.AttributeLists) + { + var nodesToRemove = attributeList.Attributes.Where(attribute => NodeHelper.AttributeNameContains(attribute, Constants.Data.BASE_PROP_NAME, Constants.Data.BASE_KNOWN_TYPE_NAME)).ToArray(); + + // If the lists are the same length, we are removing all attributes and can just avoid populating newAttributes. + if (nodesToRemove.Length != attributeList.Attributes.Count) + { + var newAttribute = (AttributeListSyntax)VisitAttributeList(attributeList.RemoveNodes(nodesToRemove, SyntaxRemoveOptions.KeepNoTrivia)); + newAttributeLists = newAttributeLists.Add(newAttribute); + } + } + var leadTriv = node.GetLeadingTrivia(); + node = node.WithAttributeLists(newAttributeLists); + node = node.WithLeadingTrivia(leadTriv); + } + + return base.VisitClassDeclaration(node); + } + + public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node) + { + if (node.AttributeLists.Count > 0) + { + var newAttributeLists = new SyntaxList(); + foreach (var attributeList in node.AttributeLists) + { + var nodesToRemove = attributeList.Attributes.Where(attribute => NodeHelper.AttributeNameContains(attribute, Constants.Data.BASE_PROP_NAME, Constants.Data.BASE_PROPIGNORE_NAME)).ToArray(); + + // If the lists are the same length, we are removing all attributes and can just avoid populating newAttributes. + if (nodesToRemove.Length != attributeList.Attributes.Count) + { + var newAttribute = (AttributeListSyntax)VisitAttributeList(attributeList.RemoveNodes(nodesToRemove, SyntaxRemoveOptions.KeepNoTrivia)); + newAttributeLists = newAttributeLists.Add(newAttribute); + } + } + var leadTriv = node.GetLeadingTrivia(); + node = node.WithAttributeLists(newAttributeLists); + node = node.WithLeadingTrivia(leadTriv); + } + + return base.VisitPropertyDeclaration(node); + } + } +} diff --git a/ProtoAttributor/Parsers/DataContracts/DataAttributeRewriter.cs b/ProtoAttributor/Parsers/DataContracts/DataAttributeRewriter.cs new file mode 100644 index 0000000..ac07276 --- /dev/null +++ b/ProtoAttributor/Parsers/DataContracts/DataAttributeRewriter.cs @@ -0,0 +1,93 @@ +using System; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Formatting; + +namespace ProtoAttributor.Parsers.DataContracts +{ + public class DataAttributeRewriter: BaseDataRewriter + { + public override int CalculateStartingIndex(SyntaxNode node) + { + return 1; + } + + public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node) + { + var hasMatch = NodeHelper.HasMatch(node.AttributeLists, Constants.Data.PROPERTY_ATTRIBUTE_NAME, Constants.Data.PROPERTY_IGNORE_ATTRIBUTE_NAME); + + if (!hasMatch) + { + var name = SyntaxFactory.ParseName(Constants.Data.PROPERTY_ATTRIBUTE_NAME); + var arguments = SyntaxFactory.ParseAttributeArgumentList($"(Order = {_startIndex})"); + var attribute = SyntaxFactory.Attribute(name, arguments); //DataMember(Order = 1) + + node = TriviaMaintainer.Apply(node, (innerNode, wp) => + { + var newAttributes = BuildAttribute(attribute, innerNode.AttributeLists, wp); + + return innerNode.WithAttributeLists(newAttributes).WithAdditionalAnnotations(Formatter.Annotation); + }); + + _startIndex++; + } + else + { + //renumber + if (node.AttributeLists.Count > 0) + { + var newAttributeLists = new SyntaxList(); + foreach (var attributeList in node.AttributeLists) + { + var attributeSyntaxes = attributeList.Attributes.Where(attribute => NodeHelper.AttributeNameMatches(attribute, Constants.Data.PROPERTY_ATTRIBUTE_NAME)).ToArray(); + + var modifiedAttributeList = attributeList.Attributes; + foreach (var attributeSyntax in attributeSyntaxes) + { + var attributeArguementSyntax = attributeSyntax.ArgumentList.Arguments.FirstOrDefault(f => f.NameEquals.Name.Identifier.ValueText.Equals("Order")); + + var newToken = SyntaxFactory.Literal(_startIndex); + var spaceTrivia = SyntaxFactory.TriviaList(SyntaxFactory.Space); + var newExpression = SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, newToken); + var equalsToken = SyntaxFactory.Token(SyntaxFactory.TriviaList(), SyntaxKind.EqualsToken, spaceTrivia); + SeparatedSyntaxList newSeparatedArgList; + if (attributeArguementSyntax?.Expression.Kind() == SyntaxKind.NumericLiteralExpression) + { + var oldToken = attributeArguementSyntax.Expression.ChildTokens().FirstOrDefault(f => f.Kind() == SyntaxKind.NumericLiteralToken); + if (oldToken == default) + { + continue; + } + var newIdentifier = attributeArguementSyntax.NameEquals.Name.Identifier.WithLeadingTrivia().WithTrailingTrivia(spaceTrivia); + var newIdentifierNameSyntax = attributeArguementSyntax.NameEquals.Name.Update(newIdentifier); + var newName = attributeArguementSyntax.NameEquals.Update(newIdentifierNameSyntax, equalsToken); + var newAttributeArguementSyntax = attributeArguementSyntax.Update(newName, null, newExpression); + newSeparatedArgList = attributeSyntax.ArgumentList.Arguments.Replace(attributeArguementSyntax, newAttributeArguementSyntax); + } + else + { + //No order attribute add it + var newIdentifierNameSyntax = SyntaxFactory.IdentifierName("Order").WithTrailingTrivia(spaceTrivia); + var newName = SyntaxFactory.NameEquals(newIdentifierNameSyntax, equalsToken); + var newAttributeArguementSyntax = SyntaxFactory.AttributeArgument(newName, null, newExpression); + newSeparatedArgList = attributeSyntax.ArgumentList.Arguments.Add(newAttributeArguementSyntax); + } + var newAttributeArgumentListSyntax = attributeSyntax.ArgumentList.WithArguments(newSeparatedArgList); + var newAttributeSyntax = attributeSyntax.Update(attributeSyntax.Name, newAttributeArgumentListSyntax); + modifiedAttributeList = modifiedAttributeList.Replace(attributeSyntax, newAttributeSyntax); + _startIndex++; + } + newAttributeLists = newAttributeLists.Add(attributeList.WithAttributes(modifiedAttributeList)); + } + var leadTriv = node.GetLeadingTrivia(); + node = node.WithAttributeLists(newAttributeLists); + node = node.WithLeadingTrivia(leadTriv); + } + } + + return base.VisitPropertyDeclaration(node); + } + } +} diff --git a/ProtoAttributor/Parsers/NodeHelper.cs b/ProtoAttributor/Parsers/NodeHelper.cs index 94ae09e..e132a13 100644 --- a/ProtoAttributor/Parsers/NodeHelper.cs +++ b/ProtoAttributor/Parsers/NodeHelper.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Simplification; -namespace ProtoAttributor.Services +namespace ProtoAttributor.Parsers { public static class NodeHelper { @@ -33,11 +33,17 @@ public static bool AttributeNameMatches(AttributeSyntax attribute, string starts .StartsWith(startsWith); } - public static bool AttributeNameMatches(AttributeSyntax attribute, params string[] startsWiths) + public static bool AttributeNameContains(AttributeSyntax attribute, params string[] startsWiths) + { + var attrName = GetSimpleNameFromNode(attribute).Identifier.Text; + return startsWiths.Any(a => attrName.StartsWith(a, StringComparison.OrdinalIgnoreCase)); + } + + public static bool AttributeNameMatches(AttributeSyntax attribute, params string[] attributeNames) { var attrName = GetSimpleNameFromNode(attribute).Identifier.Text; - return startsWiths.Contains(attrName, StringComparer.OrdinalIgnoreCase); + return attributeNames.Contains(attrName, StringComparer.OrdinalIgnoreCase); } public static bool HasMatch(SyntaxList attributeLists, string matchName) diff --git a/ProtoAttributor/Parsers/BaseProtoRewriter.cs b/ProtoAttributor/Parsers/ProtoContracts/BaseProtoRewriter.cs similarity index 94% rename from ProtoAttributor/Parsers/BaseProtoRewriter.cs rename to ProtoAttributor/Parsers/ProtoContracts/BaseProtoRewriter.cs index 4102741..2d6c2a2 100644 --- a/ProtoAttributor/Parsers/BaseProtoRewriter.cs +++ b/ProtoAttributor/Parsers/ProtoContracts/BaseProtoRewriter.cs @@ -3,8 +3,9 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; +using ProtoAttributor.Parsers; -namespace ProtoAttributor.Services +namespace ProtoAttributor.Parsers.ProtoContracts { public abstract class BaseProtoRewriter: CSharpSyntaxRewriter { diff --git a/ProtoAttributor/Parsers/ProtoAttributeAdder.cs b/ProtoAttributor/Parsers/ProtoContracts/ProtoAttributeAdder.cs similarity index 90% rename from ProtoAttributor/Parsers/ProtoAttributeAdder.cs rename to ProtoAttributor/Parsers/ProtoContracts/ProtoAttributeAdder.cs index 5cd5dae..87aa97f 100644 --- a/ProtoAttributor/Parsers/ProtoAttributeAdder.cs +++ b/ProtoAttributor/Parsers/ProtoContracts/ProtoAttributeAdder.cs @@ -2,8 +2,10 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; +using ProtoAttributor.Parsers; +using ProtoAttributor.Parsers.ProtoContracts; -namespace ProtoAttributor.Services +namespace ProtoAttributor.Parsers.ProtoContracts { public class ProtoAttributeAdder: BaseProtoRewriter { diff --git a/ProtoAttributor/Parsers/ProtoAttributeReader.cs b/ProtoAttributor/Parsers/ProtoContracts/ProtoAttributeReader.cs similarity index 92% rename from ProtoAttributor/Parsers/ProtoAttributeReader.cs rename to ProtoAttributor/Parsers/ProtoContracts/ProtoAttributeReader.cs index 4b23efe..0c31e20 100644 --- a/ProtoAttributor/Parsers/ProtoAttributeReader.cs +++ b/ProtoAttributor/Parsers/ProtoContracts/ProtoAttributeReader.cs @@ -2,8 +2,9 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using ProtoAttributor.Parsers; -namespace ProtoAttributor.Services +namespace ProtoAttributor.Parsers.ProtoContracts { public class ProtoAttributeReader: CSharpSyntaxWalker { diff --git a/ProtoAttributor/Parsers/ProtoAttributeRemover.cs b/ProtoAttributor/Parsers/ProtoContracts/ProtoAttributeRemover.cs similarity index 95% rename from ProtoAttributor/Parsers/ProtoAttributeRemover.cs rename to ProtoAttributor/Parsers/ProtoContracts/ProtoAttributeRemover.cs index d4c7b34..04985ca 100644 --- a/ProtoAttributor/Parsers/ProtoAttributeRemover.cs +++ b/ProtoAttributor/Parsers/ProtoContracts/ProtoAttributeRemover.cs @@ -2,8 +2,9 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; +using ProtoAttributor.Parsers; -namespace ProtoAttributor.Services +namespace ProtoAttributor.Parsers.ProtoContracts { public class ProtoAttributeRemover: CSharpSyntaxRewriter { diff --git a/ProtoAttributor/Parsers/ProtoAttributeRewriter.cs b/ProtoAttributor/Parsers/ProtoContracts/ProtoAttributeRewriter.cs similarity index 94% rename from ProtoAttributor/Parsers/ProtoAttributeRewriter.cs rename to ProtoAttributor/Parsers/ProtoContracts/ProtoAttributeRewriter.cs index 386bede..dad5a02 100644 --- a/ProtoAttributor/Parsers/ProtoAttributeRewriter.cs +++ b/ProtoAttributor/Parsers/ProtoContracts/ProtoAttributeRewriter.cs @@ -3,8 +3,10 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Formatting; +using ProtoAttributor.Parsers; +using ProtoAttributor.Parsers.ProtoContracts; -namespace ProtoAttributor.Services +namespace ProtoAttributor.Parsers.ProtoContracts { public class ProtoAttributeRewriter: BaseProtoRewriter { diff --git a/ProtoAttributor/Parsers/TriviaMaintainer.cs b/ProtoAttributor/Parsers/TriviaMaintainer.cs index 9d3c05a..221bbdb 100644 --- a/ProtoAttributor/Parsers/TriviaMaintainer.cs +++ b/ProtoAttributor/Parsers/TriviaMaintainer.cs @@ -4,7 +4,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; -namespace ProtoAttributor.Services +namespace ProtoAttributor.Parsers { public static class TriviaMaintainer { diff --git a/ProtoAttributor/ProtoAttributor.csproj b/ProtoAttributor/ProtoAttributor.csproj index aac32cf..73708f4 100644 --- a/ProtoAttributor/ProtoAttributor.csproj +++ b/ProtoAttributor/ProtoAttributor.csproj @@ -57,8 +57,13 @@ - - + + + + + + + @@ -66,10 +71,10 @@ - + - - + + @@ -109,7 +114,10 @@ Always true + + + diff --git a/ProtoAttributor/ProtoAttributorPackage.cs b/ProtoAttributor/ProtoAttributorPackage.cs index 74c093c..6b4e114 100644 --- a/ProtoAttributor/ProtoAttributorPackage.cs +++ b/ProtoAttributor/ProtoAttributorPackage.cs @@ -1,8 +1,11 @@ using System; using System.Runtime.InteropServices; using System.Threading; +using DataAttributor.Services; using Microsoft.VisualStudio.Shell; using ProtoAttributor.Commands.Context; +using ProtoAttributor.Parsers.DataContracts; +using ProtoAttributor.Parsers.ProtoContracts; using ProtoAttributor.Services; using Task = System.Threading.Tasks.Task; @@ -58,13 +61,13 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke AddService(typeof(IProtoAttributeService), protoCallback, true); - //var datAnnoCallback = new AsyncServiceCreatorCallback(async (IAsyncServiceContainer container, CancellationToken ct, Type serviceType) => - //{ - // if (typeof(IDataAnnoAttributeService) == serviceType) - // return new DataAnnoAttributeService(this, new ProtoAttributeAdder(), new ProtoAttributeReader(), new ProtoAttributeRemover(), new ProtoAttributeRewriter()); - // return null; - //}); - //AddService(typeof(IDataAnnoAttributeService), datAnnoCallback, true); + var datAnnoCallback = new AsyncServiceCreatorCallback(async (IAsyncServiceContainer container, CancellationToken ct, Type serviceType) => + { + if (typeof(IDataAnnoAttributeService) == serviceType) + return new DataAnnoAttributeService(this, new DataAttributeAdder(), new DataAttributeRemover(), new DataAttributeRewriter()); + return null; + }); + AddService(typeof(IDataAnnoAttributeService), datAnnoCallback, true); // When initialized asynchronously, the current thread may be a background thread at this point. Do any // initialization that requires the UI thread after switching to the UI thread. @@ -74,16 +77,16 @@ await Task.WhenAll( ProtoAddAttrCommand.InitializeAsync(this), ProtoRenumberAttrCommand.InitializeAsync(this), ProtoRemoveAttrCommand.InitializeAsync(this), - //DataAnnoAddAttrCommand.InitializeAsync(this), - //DataAnnoRenumberAttrCommand.InitializeAsync(this), - //DataAnnoRemoveAttrCommand.InitializeAsync(this), + DataAnnoAddAttrCommand.InitializeAsync(this), + DataAnnoRenumberAttrCommand.InitializeAsync(this), + DataAnnoRemoveAttrCommand.InitializeAsync(this), Commands.Menu.ProtoAddAttrCommand.InitializeAsync(this), Commands.Menu.ProtoRenumberAttrCommand.InitializeAsync(this), - Commands.Menu.ProtoRemoveAttrCommand.InitializeAsync(this) - //Commands.Menu.DataAnnoAddAttrCommand.InitializeAsync(this), - //Commands.Menu.DataAnnoRenumberAttrCommand.InitializeAsync(this), - //Commands.Menu.DataAnnoRemoveAttrCommand.InitializeAsync(this) + Commands.Menu.ProtoRemoveAttrCommand.InitializeAsync(this), + Commands.Menu.DataAnnoAddAttrCommand.InitializeAsync(this), + Commands.Menu.DataAnnoRenumberAttrCommand.InitializeAsync(this), + Commands.Menu.DataAnnoRemoveAttrCommand.InitializeAsync(this) ); diff --git a/ProtoAttributor/ProtoAttributorPackage.vsct b/ProtoAttributor/ProtoAttributorPackage.vsct index 00803a6..89f3f1f 100644 --- a/ProtoAttributor/ProtoAttributorPackage.vsct +++ b/ProtoAttributor/ProtoAttributorPackage.vsct @@ -42,18 +42,18 @@ - + - + diff --git a/ProtoAttributor/ProtoImagePreview.jpg b/ProtoAttributor/ProtoImagePreview.jpg index c6f8b22..c0cfaa1 100644 Binary files a/ProtoAttributor/ProtoImagePreview.jpg and b/ProtoAttributor/ProtoImagePreview.jpg differ diff --git a/ProtoAttributor/Resources/DataContractVideo.mp4 b/ProtoAttributor/Resources/DataContractVideo.mp4 new file mode 100644 index 0000000..f95236b Binary files /dev/null and b/ProtoAttributor/Resources/DataContractVideo.mp4 differ diff --git a/ProtoAttributor/Resources/ProtoContractVideo.mp4 b/ProtoAttributor/Resources/ProtoContractVideo.mp4 new file mode 100644 index 0000000..08ea2c1 Binary files /dev/null and b/ProtoAttributor/Resources/ProtoContractVideo.mp4 differ diff --git a/ProtoAttributor/Resources/SinglePageProtoActions.mp4 b/ProtoAttributor/Resources/SinglePageProtoActions.mp4 new file mode 100644 index 0000000..8afa97c Binary files /dev/null and b/ProtoAttributor/Resources/SinglePageProtoActions.mp4 differ diff --git a/ProtoAttributor/Services/DataAnnoAttributeService.cs b/ProtoAttributor/Services/DataAnnoAttributeService.cs index 2b421c7..8589be8 100644 --- a/ProtoAttributor/Services/DataAnnoAttributeService.cs +++ b/ProtoAttributor/Services/DataAnnoAttributeService.cs @@ -1,23 +1,23 @@ using Microsoft.CodeAnalysis.CSharp; +using ProtoAttributor.Parsers.DataContracts; +using ProtoAttributor.Services; -namespace ProtoAttributor.Services +namespace DataAttributor.Services { public class DataAnnoAttributeService: IDataAnnoAttributeService { private readonly Microsoft.VisualStudio.OLE.Interop.IServiceProvider _serviceProvider; - private readonly ProtoAttributeAdder _adder; - private readonly ProtoAttributeReader _protoReader; - private readonly ProtoAttributeRemover _remover; - private readonly ProtoAttributeRewriter _rewriter; + private readonly DataAttributeAdder _adder; + private readonly DataAttributeRemover _remover; + private readonly DataAttributeRewriter _rewriter; public DataAnnoAttributeService(Microsoft.VisualStudio.OLE.Interop.IServiceProvider sp, - ProtoAttributeAdder adder, ProtoAttributeReader reader, ProtoAttributeRemover remover, ProtoAttributeRewriter rewriter) + DataAttributeAdder adder, DataAttributeRemover remover, DataAttributeRewriter rewriter) { _serviceProvider = sp; //TODO: move to an injection _adder = adder; - _protoReader = reader; _remover = remover; _rewriter = rewriter; } diff --git a/ProtoAttributor/Services/ProtoAttributeService.cs b/ProtoAttributor/Services/ProtoAttributeService.cs index bc3b889..c3ed45f 100644 --- a/ProtoAttributor/Services/ProtoAttributeService.cs +++ b/ProtoAttributor/Services/ProtoAttributeService.cs @@ -1,4 +1,5 @@ using Microsoft.CodeAnalysis.CSharp; +using ProtoAttributor.Parsers.ProtoContracts; namespace ProtoAttributor.Services { diff --git a/ProtoAttributor/source.extension.vsixmanifest b/ProtoAttributor/source.extension.vsixmanifest index 649c2bb..b96700d 100644 --- a/ProtoAttributor/source.extension.vsixmanifest +++ b/ProtoAttributor/source.extension.vsixmanifest @@ -1,10 +1,11 @@ - + ProtoAttributor - ProtoAttributor is an open source Visual Studio extension that can manage the appropriate attributes on a class to support ProtoBuf. It currently supports ProtoContract, ProtoMember, ProtoIgnore attributes. This extension lets you Add, Reorder, and Remove ProtoBuf attributes from a class. + ProtoAttributor is an open source Visual Studio extension that can manage the appropriate attributes on a class to support ProtoBuf. It currently supports ProtoContract, ProtoMember, ProtoIgnore, DataContract, DataMember, IgnoreDataMemeber attributes. This extension lets you Add, Reorder, and Remove ProtoBuf attributes from a class. This works in conjunction with the protobuf-net 3.0+ Nuget package https://github.com/d1820/proto-attributor + https://github.com/d1820/proto-attributor/releases logo.png ProtoImagePreview.jpg ProtoBuf, ProtoBuf-Net, Code, Build, ReFormatting, Organizing, Attributing, Contracts, Serialization diff --git a/README.md b/README.md index 4c1f320..628ddf3 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ # ![alt text](./ProtoAttributor/logo.png "ProtoAttributor") -ProtoAttributor is an open source Visual Studio extension that can manage the appropriate attributes on a class to support ProtoBuf. It currently supports ProtoContract, ProtoMember, ProtoIgnore attributes. This extension lets you Add, Reorder, and Remove ProtoBuf attributes from a class. +ProtoAttributor is an open source Visual Studio extension that can manage the appropriate attributes on a class to support ProtoBuf. +It currently supports ProtoContract, ProtoMember, ProtoIgnore, DataContract, DataMember, IgnoreDataMemeber attributes. This extension lets you Add, Reorder, and Remove ProtoBuf attributes from a class. +This works in conjunction with the [protobuf-net](https://github.com/protobuf-net/protobuf-net) 3.0+ Nuget package -One of the challenges with creating proper ProtoBuf contracts is getting the ordering correct and consistent. + +One of the challenges with creating proper ProtoBuf contracts is getting the ordering correct and consistent. While small contract classes are easy to manage as classes get larger or lots of nested classes are created it gets harder and harder to manage and maintain these classes. This is where ProtoAttributor shines. You can Add, Reorder, Remove ProtoBuf attributes from 1 or many classes. @@ -23,13 +26,31 @@ This is helpful when contracts have not been releases yet and you want to ensure Removing attributes will not only remove the ProtoMember attributes but also includes any attribute or using that is related to [Proto*] family. - - ## Ways to Use ProtoAttributor can handle single files already open in Visual Studio from the Tools menu or it can handle entire directories of files from the solution explorer. +## Proto[Attributor] In Action + +### Working With ProtoMembers + + + +### Working With DataMembers + + + +### Working With A Single File + + + - + Special thanks to logomakr.com for the logo