Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Suppress collection methods #41

Merged
merged 6 commits into from
Mar 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ PM> Install-Package M31.FluentApi
A package reference will be added to your `csproj` file. Moreover, since this library provides code via source code generation, consumers of your project don't need the reference to `M31.FluentApi`. Therefore, it is recommended to use the `PrivateAssets` metadata tag:

```xml
<PackageReference Include="M31.FluentApi" Version="1.9.1" PrivateAssets="all"/>
<PackageReference Include="M31.FluentApi" Version="1.10.0" PrivateAssets="all"/>
```

If you would like to examine the generated code, you may emit it by adding the following lines to your `csproj` file:
Expand Down Expand Up @@ -222,11 +222,11 @@ FluentCollection(
int builderStep,
string singularName,
string withItems = "With{Name}",
string withItem = "With{SingularName}",
string withZeroItems = "WithZero{Name}")
string? withItem = "With{SingularName}",
string? withZeroItems = "WithZero{Name}")
```

Can be used instead of the `FluentMember` attribute if the decorated member is a collection. This attribute generates methods for setting multiple items, one item and zero items. The supported collection types can be seen in the source file [CollectionInference.cs](src/M31.FluentApi.Generator/SourceGenerators/Collections/CollectionInference.cs).
Can be used instead of the `FluentMember` attribute if the decorated member is a collection. This attribute generates methods for setting multiple items, one item and zero items. The supported collection types can be seen in the source file [CollectionInference.cs](src/M31.FluentApi.Generator/SourceGenerators/Collections/CollectionInference.cs). If `withItem` or `withZeroItems` is set to `null`, the corresponding method will not be generated.

```cs
[FluentCollection(5, "Friend", "WhoseFriendsAre", "WhoseFriendIs", "WhoHasNoFriends")]
Expand Down
2 changes: 2 additions & 0 deletions src/ExampleProject/Program.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System.Text.Json;
using ExampleProject;

#pragma warning disable CS8321 // Local function is declared but never used

// Student
//

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,13 @@ internal BuilderMethod CreateWithItemsParamsMethod(MethodCreator methodCreator)
computeValueCode);
}

internal BuilderMethod CreateWithItemMethod(MethodCreator methodCreator)
internal BuilderMethod? CreateWithItemMethod(MethodCreator methodCreator)
{
if (collectionAttributeInfo.WithItem == null)
{
return null;
}

Parameter parameter = new Parameter(genericTypeArgument, collectionAttributeInfo.SingularNameInCamelCase);
return methodCreator.CreateMethodWithComputedValue(
symbolInfo,
Expand All @@ -101,7 +106,7 @@ internal BuilderMethod CreateWithItemMethod(MethodCreator methodCreator)

internal BuilderMethod? CreateWithItemLambdaMethod(MethodCreator methodCreator)
{
if (collectionAttributeInfo.LambdaBuilderInfo == null)
if (collectionAttributeInfo.WithItem == null || collectionAttributeInfo.LambdaBuilderInfo == null)
{
return null;
}
Expand All @@ -123,8 +128,13 @@ internal BuilderMethod CreateWithItemMethod(MethodCreator methodCreator)
computeValueCode);
}

internal BuilderMethod CreateWithZeroItemsMethod(MethodCreator methodCreator)
internal BuilderMethod? CreateWithZeroItemsMethod(MethodCreator methodCreator)
{
if (collectionAttributeInfo.WithZeroItems == null)
{
return null;
}

string collectionWithZeroItemsCode = CreateCollectionWithZeroItems(genericTypeArgument);
return methodCreator.CreateMethodWithFixedValue(
symbolInfo,
Expand Down
2 changes: 1 addition & 1 deletion src/M31.FluentApi.Generator/M31.FluentApi.Generator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
<PackageVersion>1.9.1</PackageVersion>
<PackageVersion>1.10.0</PackageVersion>
<Authors>Kevin Schaal</Authors>
<Description>The generator package for M31.FluentAPI. Don't install this package explicitly, install M31.FluentAPI instead.</Description>
<PackageTags>fluentapi fluentbuilder fluentinterface fluentdesign fluent codegeneration</PackageTags>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ private FluentCollectionAttributeInfo(
int builderStep,
string singularName,
string withItems,
string withItem,
string withZeroItems,
string? withItem,
string? withZeroItems,
LambdaBuilderInfo? lambdaBuilderInfo)
: base(builderStep)
{
Expand All @@ -26,8 +26,8 @@ private FluentCollectionAttributeInfo(
internal string SingularName { get; }
internal string SingularNameInCamelCase { get; }
internal string WithItems { get; }
internal string WithItem { get; }
internal string WithZeroItems { get; }
internal string? WithItem { get; }
internal string? WithZeroItems { get; }
internal LambdaBuilderInfo? LambdaBuilderInfo { get; }
internal override string FluentMethodName => WithItems;

Expand All @@ -36,12 +36,20 @@ internal static FluentCollectionAttributeInfo Create(
string memberName,
LambdaBuilderInfo? lambdaBuilderInfo)
{
(int builderStep, string singularName, string withItems, string withItem, string withZeroItems) =
attributeData.GetConstructorArguments<int, string, string, string, string>();
(int builderStep, string singularName, string withItems, string? withItem, string? withZeroItems) =
attributeData.GetConstructorArguments<int, string, string, string?, string?>();

withItems = NameCreator.CreateName(withItems, memberName, singularName);
withItem = NameCreator.CreateName(withItem, memberName, singularName);
withZeroItems = NameCreator.CreateName(withZeroItems, memberName, singularName);

if (withItem != null)
{
withItem = NameCreator.CreateName(withItem, memberName, singularName);
}

if (withZeroItems != null)
{
withZeroItems = NameCreator.CreateName(withZeroItems, memberName, singularName);
}

return new FluentCollectionAttributeInfo(
builderStep, singularName, withItems, withItem, withZeroItems, lambdaBuilderInfo);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// <auto-generated/>
// This code was generated by the library M31.FluentAPI.
// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
#nullable enable

using System.Collections.Generic;

namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.CollectionMemberClassWithSuppression;

public class CreateStudent :
CreateStudent.ICreateStudent,
CreateStudent.IWhoseFriendsAre,
CreateStudent.IWithPets,
CreateStudent.IWithBackpackContent
{
private readonly Student student;

private CreateStudent()
{
student = new Student();
}

public static ICreateStudent InitialStep()
{
return new CreateStudent();
}

public static IWithPets WhoseFriendsAre(System.Collections.Generic.List<string> friends)
{
CreateStudent createStudent = new CreateStudent();
createStudent.student.Friends = friends;
return createStudent;
}

public static IWithPets WhoseFriendsAre(params string[] friends)
{
CreateStudent createStudent = new CreateStudent();
createStudent.student.Friends = new List<string>(friends);
return createStudent;
}

IWithPets IWhoseFriendsAre.WhoseFriendsAre(System.Collections.Generic.List<string> friends)
{
student.Friends = friends;
return this;
}

IWithPets IWhoseFriendsAre.WhoseFriendsAre(params string[] friends)
{
student.Friends = new List<string>(friends);
return this;
}

IWithBackpackContent IWithPets.WithPets(params string[] pets)
{
student.Pets = pets;
return this;
}

Student IWithBackpackContent.WithBackpackContent(System.Collections.Generic.HashSet<string> backpackContent)
{
student.BackpackContent = backpackContent;
return student;
}

Student IWithBackpackContent.WithBackpackContent(params string[] backpackContent)
{
student.BackpackContent = new HashSet<string>(backpackContent);
return student;
}

public interface ICreateStudent : IWhoseFriendsAre
{
}

public interface IWhoseFriendsAre
{
IWithPets WhoseFriendsAre(System.Collections.Generic.List<string> friends);

IWithPets WhoseFriendsAre(params string[] friends);
}

public interface IWithPets
{
IWithBackpackContent WithPets(params string[] pets);
}

public interface IWithBackpackContent
{
Student WithBackpackContent(System.Collections.Generic.HashSet<string> backpackContent);

Student WithBackpackContent(params string[] backpackContent);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// <auto-generated/>
// This code was generated by the library M31.FluentAPI.
// Changes to this file may cause incorrect behavior and will be lost if the code is regenerated.

#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member
#nullable enable

using System.Collections.Generic;

namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.CollectionMemberClassWithSuppression;

public class CreateStudent :
CreateStudent.ICreateStudent,
CreateStudent.IWhoseFriendsAre,
CreateStudent.IWithPets,
CreateStudent.IWithBackpackContent
{
private readonly Student student;

private CreateStudent()
{
student = new Student();
}

public static ICreateStudent InitialStep()
{
return new CreateStudent();
}

public static IWithPets WhoseFriendsAre(System.Collections.Generic.List<string> friends)
{
CreateStudent createStudent = new CreateStudent();
createStudent.student.Friends = friends;
return createStudent;
}

public static IWithPets WhoseFriendsAre(params string[] friends)
{
CreateStudent createStudent = new CreateStudent();
createStudent.student.Friends = new List<string>(friends);
return createStudent;
}

IWithPets IWhoseFriendsAre.WhoseFriendsAre(System.Collections.Generic.List<string> friends)
{
student.Friends = friends;
return this;
}

IWithPets IWhoseFriendsAre.WhoseFriendsAre(params string[] friends)
{
student.Friends = new List<string>(friends);
return this;
}

IWithBackpackContent IWithPets.WithPets(params string[] pets)
{
student.Pets = pets;
return this;
}

Student IWithBackpackContent.WithBackpackContent(System.Collections.Generic.HashSet<string> backpackContent)
{
student.BackpackContent = backpackContent;
return student;
}

Student IWithBackpackContent.WithBackpackContent(params string[] backpackContent)
{
student.BackpackContent = new HashSet<string>(backpackContent);
return student;
}

public interface ICreateStudent : IWhoseFriendsAre
{
}

public interface IWhoseFriendsAre
{
IWithPets WhoseFriendsAre(System.Collections.Generic.List<string> friends);

IWithPets WhoseFriendsAre(params string[] friends);
}

public interface IWithPets
{
IWithBackpackContent WithPets(params string[] pets);
}

public interface IWithBackpackContent
{
Student WithBackpackContent(System.Collections.Generic.HashSet<string> backpackContent);

Student WithBackpackContent(params string[] backpackContent);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Non-nullable member is uninitialized
#pragma warning disable CS8618
// ReSharper disable All

using System.Collections.Generic;
using M31.FluentApi.Attributes;

namespace M31.FluentApi.Tests.CodeGeneration.TestClasses.Abstract.CollectionMemberClassWithSuppression;

[FluentApi]
public class Student
{
[FluentCollection(0, "Friend", "WhoseFriendsAre", null, null)]
public List<string> Friends { get; set; }

[FluentCollection(1, "Pet", withItem: null, withZeroItems: null)]
public string[] Pets { get; set; }

[FluentCollection(2, "BackpackContent", "WithBackpackContent", null, null)]
public HashSet<string> BackpackContent { get; set; }
}
1 change: 1 addition & 0 deletions src/M31.FluentApi.Tests/CodeGeneration/TestDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ internal class TestDataProvider : IEnumerable<object[]>
new object[] { "Abstract", "AliasNamespaceClass", "Student" },
new object[] { "Abstract", "CollectionInterfaceMemberClass", "Student" },
new object[] { "Abstract", "CollectionMemberClass", "Student" },
new object[] { "Abstract", "CollectionMemberClassWithSuppression", "Student" },
new object[] { "Abstract", "CollectionNullableArrayClass", "Student" },
new object[] { "Abstract", "ContinueWithAfterCompoundClass", "Student" },
new object[] { "Abstract", "ContinueWithInForkClass", "Student" },
Expand Down
10 changes: 5 additions & 5 deletions src/M31.FluentApi/Attributes/FluentCollectionAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ public class FluentCollectionAttribute : Attribute
/// <param name="builderStep">The builder step in which the collection can be set.</param>
/// <param name="singularName">The singular of the collection name.</param>
/// <param name="withItems">The name of the builder method that sets multiple items.</param>
/// <param name="withItem">The name of the builder method that sets a single item.</param>
/// <param name="withItem">The name of the builder method that sets a single item.
/// If set to null, the builder method will not be generated.</param>
/// <param name="withZeroItems">The name of the builder method that sets zero items.
/// </param>
/// If set to null, the builder method will not be generated.</param>
public FluentCollectionAttribute(
int builderStep,
string singularName,
string withItems = "With{Name}",
string withItem = "With{SingularName}",
string withZeroItems = "WithZero{Name}")
string? withItem = "With{SingularName}",
string? withZeroItems = "WithZero{Name}")
{

}
}
2 changes: 1 addition & 1 deletion src/M31.FluentApi/M31.FluentApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageVersion>1.9.1</PackageVersion>
<PackageVersion>1.10.0</PackageVersion>
<Authors>Kevin Schaal</Authors>
<Description>Generate fluent builders in C#.</Description>
<PackageTags>fluentapi fluentbuilder fluentinterface fluentdesign fluent codegeneration</PackageTags>
Expand Down