@@ -19,9 +19,10 @@ Instructions on development and using this project's source code are in [CONTRIB
1919 - [ Table of Contents] ( #table-of-contents )
2020 - [ How to write your own code generator] ( #how-to-write-your-own-code-generator )
2121 - [ Prerequisites] ( #prerequisites )
22+ - [ Use template pack] ( #use-template-pack )
2223 - [ Define code generator] ( #define-code-generator )
23- - [ Create consuming console app] ( #create-consuming-console-app )
2424 - [ Define attribute] ( #define-attribute )
25+ - [ Create consuming console app] ( #create-consuming-console-app )
2526 - [ Apply code generation] ( #apply-code-generation )
2627 - [ Advanced scenarios] ( #advanced-scenarios )
2728 - [ Customize generator reference] ( #customize-generator-reference )
@@ -44,6 +45,63 @@ In this walkthrough, we will define a code generator that replicates any class (
4445
4546[ dotnet-sdk-2.1 ] : https://dotnet.microsoft.com/download/dotnet-core/2.1
4647
48+ ### Use template pack
49+
50+ To install the template pack, run:
51+ > ` dotnet new -i CodeGeneration.Roslyn.Templates `
52+
53+ You'll then have our template pack installed and ready for use with ` dotnet new ` .
54+ For details see [ templates Readme] ( ./templates/README.md ) .
55+
56+ Prepare a directory where you want to create your Plugin projects, e.g. ` mkdir DemoGeneration ` .
57+ Then, in that directory, create the set of Plugin projects (we add the --sln to create solution as well):
58+ > ` dotnet new cgrplugin -n Duplicator --sln `
59+
60+ This will create 3 ready-to-build projects. You can now skip through the next steps
61+ of creating and setting up projects, just apply the following changes to have the same content:
62+ - rename ` Duplicator.Generators/Generator1.cs ` to ` DuplicateWithSuffixGenerator.cs `
63+ - also replace the ` DuplicateWithSuffixGenerator ` class with the following:
64+ ``` csharp
65+ public class DuplicateWithSuffixGenerator : ICodeGenerator
66+ {
67+ private readonly string suffix ;
68+
69+ public DuplicateWithSuffixGenerator (AttributeData attributeData )
70+ {
71+ suffix = (string )attributeData .ConstructorArguments [0 ].Value ;
72+ }
73+
74+ public Task <SyntaxList <MemberDeclarationSyntax >> GenerateAsync (TransformationContext context , IProgress <Diagnostic > progress , CancellationToken cancellationToken )
75+ {
76+ // Our generator is applied to any class that our attribute is applied to.
77+ var applyToClass = (ClassDeclarationSyntax )context .ProcessingNode ;
78+
79+ // Apply a suffix to the name of a copy of the class.
80+ var copy = applyToClass .WithIdentifier (SyntaxFactory .Identifier (applyToClass .Identifier .ValueText + suffix ));
81+
82+ // Return our modified copy. It will be added to the user's project for compilation.
83+ var results = SyntaxFactory .SingletonList <MemberDeclarationSyntax >(copy );
84+ return Task .FromResult (results );
85+ }
86+ }
87+ ```
88+ - rename `Duplicator .Attributes / Generator1Attribute .cs ` file to `DuplicateWithSuffixAttribute .cs `
89+ - also replace `DuplicateWithSuffixAttribute ` class with the following:
90+ ```csharp
91+ [AttributeUsage(AttributeTargets.Class)]
92+ [CodeGenerationAttribute("Duplicator.Generators.DuplicateWithSuffixGenerator, Duplicator.Generators")]
93+ [Conditional("CodeGeneration")]
94+ public class DuplicateWithSuffixAttribute : Attribute
95+ {
96+ public DuplicateWithSuffixAttribute (string suffix )
97+ {
98+ Suffix = suffix ;
99+ }
100+
101+ public string Suffix { get ; }
102+ }
103+ ```
104+
47105### Define code generator
48106
49107Your generator cannot be defined in the same project that will have code generated
@@ -57,7 +115,7 @@ Now we'll use an [MSBuild project SDK] [`CodeGeneration.Roslyn.Plugin.Sdk`][Plug
57115<!-- Duplicator.Generators/Duplicator.Generators.csproj -->
58116<Project Sdk="Microsoft.NET.Sdk">
59117 <!-- Add the following element above any others: -->
60- <Sdk Name =" CodeGeneration.Roslyn.Plugin.Sdk" Version =" {replace with actual version used}" />
118+ <Sdk Name="CodeGeneration.Roslyn.Plugin.Sdk" Version="{replace with actual version used}" />
61119
62120 < PropertyGroup >
63121 < TargetFramework > netcoreapp2 .1 < / TargetFramework >
@@ -107,56 +165,26 @@ namespace Duplicator.Generators
107165}
108166```
109167
110- ### Create consuming console app
111-
112- We'll consume our generator in a Reflector app:
113- > ` dotnet new console -f netcoreapp2.1 -o Reflector `
114- >
115- > ` dotnet add Reflector reference Duplicator.Generators `
116-
117- Let's write a simple program that prints all types in its assembly:
118- ``` csharp
119- // Reflector/Program.cs
120- using System ;
121-
122- namespace Reflector
123- {
124- class Program
125- {
126- static void Main (string [] args )
127- {
128- foreach (var type in typeof (Program ).Assembly .GetTypes ())
129- Console .WriteLine (type .FullName );
130- }
131- }
132- }
133- ```
134-
135- Now, when we ` dotnet run -p Reflector ` we should get:
136- > ` Reflector.Program `
137-
138168### Define attribute
139169
140170To activate your code generator, you need to define an attribute with which
141- we'll annotate the class to be copied. Install [ Attributes package] [ AttrNuPkg ] :
171+ we'll annotate the class to be copied. Let's do that in a new project:
172+ > ` dotnet new classlib -f netstandard2.0 -o Duplicator.Attributes `
142173
143- > ` dotnet add Reflector package CodeGeneration.Roslyn.Attributes `
174+ Install [ Attributes package] [ AttrNuPkg ] :
175+
176+ > ` dotnet add Duplicator.Attributes package CodeGeneration.Roslyn.Attributes `
144177
145178Then, define your attribute class:
146179
147180``` csharp
148- // Reflector/Program .cs
181+ // Duplicator.Attributes/DuplicateWithSuffixAttribute .cs
149182using System ;
150183using System .Diagnostics ;
151184using CodeGeneration .Roslyn ;
152185
153- namespace Reflector
186+ namespace Duplicator
154187{
155- class Program
156- {
157- // ...
158- }
159-
160188 [AttributeUsage (AttributeTargets .Class )]
161189 [CodeGenerationAttribute (" Duplicator.Generators.DuplicateWithSuffixGenerator, Duplicator.Generators" )]
162190 [Conditional (" CodeGeneration" )]
@@ -185,6 +213,36 @@ with a dependency on your code generation assembly.
185213> ℹ Of course, the attribute will persist if you define compilation symbol
186214> "CodeGeneration"; we assume it won't be defined.
187215
216+ ### Create consuming console app
217+
218+ We'll consume our generator in a Reflector app:
219+ > ` dotnet new console -o Reflector `
220+ >
221+ > ` dotnet add Reflector reference Duplicator.Attributes `
222+ >
223+ > ` dotnet add Reflector reference Duplicator.Generators `
224+
225+ Let's write a simple program that prints all types in its assembly:
226+ ``` csharp
227+ // Reflector/Program.cs
228+ using System ;
229+
230+ namespace Reflector
231+ {
232+ class Program
233+ {
234+ static void Main (string [] args )
235+ {
236+ foreach (var type in typeof (Program ).Assembly .GetTypes ())
237+ Console .WriteLine (type .FullName );
238+ }
239+ }
240+ }
241+ ```
242+
243+ Now, when we ` dotnet run -p Reflector ` we should get:
244+ > ` Reflector.Program `
245+
188246### Apply code generation
189247
190248Applying code generation is incredibly simple. Just add the attribute on any type
@@ -195,6 +253,7 @@ or member supported by the attribute and generator you wrote. We'll test our Dup
195253using System ;
196254using System .Diagnostics ;
197255using CodeGeneration .Roslyn ;
256+ using Duplicator ;
198257
199258namespace Reflector
200259{
@@ -205,19 +264,12 @@ namespace Reflector
205264 {
206265 // ...
207266 }
208-
209- class DuplicateWithSuffixAttribute : Attribute
210- {
211- // ...
212- }
213267}
214268```
215269
216270Let's check our app again:
217271> ` > dotnet run -p Reflector `
218272>
219- > ` Reflector.DuplicateWithSuffixAttribute `
220- >
221273> ` Reflector.Program `
222274>
223275> ` Reflector.Test `
@@ -261,8 +313,6 @@ This is how your project file can look like:
261313And if all steps were done correctly:
262314> ` > dotnet run -p Reflector `
263315>
264- > ` Reflector.DuplicateWithSuffixAttribute `
265- >
266316> ` Reflector.Program `
267317>
268318> ` Reflector.Test `
@@ -354,12 +404,16 @@ we have to use `SetTargetFramework` metadata. Setting it implies
354404
355405### Package your code generator
356406
407+ > ℹ If you've used ` cgrplugin ` template, you've already got metapackage project ready.
408+
357409You can also package up your code generator as a NuGet package for others to install
358410and use. A project using ` CodeGeneration.Roslyn.Plugin.Sdk ` is automatically
359411configured to produce a correct Plugin nuget package.
360412
361413#### Separate out the attribute
362414
415+ > ⚠ This section is deprecated since it's now the default.
416+
363417The triggering attribute has to be available in consuming code. Your consumers
364418can write it themselves, but it's not a good idea to require them do so.
365419So we'll separate the attribute into another project that has TFM allowing
@@ -398,7 +452,7 @@ An example consuming project file would contain:
398452</ItemGroup >
399453```
400454
401- > ➡ There's a much better approach: ** metapackage** .
455+ > ✔ There's a much better approach: ** metapackage** .
402456
403457For this, we'll use [ ` CodeGeneration.Roslyn.PluginMetapackage.Sdk ` ] [ PluginMetapkgSdkNuPkg ] [ MSBuild project SDK]
404458in a new project called simply ` Duplicator ` , which will reference our attributes:
0 commit comments