Getting Started
Getting Started
Section titled “Getting Started”Install
Section titled “Install”dotnet add package Purview.SourceGeneratorFrameworkReference the package from a Roslyn source generator project:
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> <IsRoslynComponent>true</IsRoslynComponent> <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules> </PropertyGroup>
<ItemGroup> <PackageReference Include="Purview.SourceGeneratorFramework" /> <PackageReference Include="Microsoft.CodeAnalysis.CSharp" PrivateAssets="all" /> <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" PrivateAssets="all" /> </ItemGroup></Project>Referencing a generator project
Section titled “Referencing a generator project”Roslyn must receive both a source-generator assembly and its framework runtime dependency as analyzer inputs. Use an analyzer project reference:
<ProjectReference Include="..\MyGenerator\MyGenerator.csproj" PrivateAssets="all" OutputItemType="Analyzer" ReferenceOutputAssembly="false"/>The Purview SDK automatically invokes GetSourceGeneratorAnalyzerFiles, which returns both the
generator and its framework dependency without adding either file to the consuming application’s
runtime references. Specifying Targets="GetSourceGeneratorAnalyzerFiles" explicitly remains
supported but is not required.
Referencing a generator from its test project
Section titled “Referencing a generator from its test project”A test project can need the source-generator project in two different roles at the same time:
- as an analyzer, so the generator runs against the test project and its generated attributes and other types can be used directly by test source files; and
- as a normal assembly reference, so the test code can name and instantiate the generator type
through
Purview.SourceGeneratorFramework.Testing.
Add two project references with deliberately different metadata:
<ItemGroup> <!-- Run the generator against this test project. --> <ProjectReference Include="..\MyGenerator\MyGenerator.csproj" PrivateAssets="all" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<!-- Make MyGenerator available to the test code and test runner. --> <ProjectReference Include="..\MyGenerator\MyGenerator.csproj" PrivateAssets="all" ReferenceOutputAssembly="true" /></ItemGroup>Do not put OutputItemType="Analyzer" on the normal reference. The Purview SDK automatically
uses GetSourceGeneratorAnalyzerFiles for the analyzer reference and supplies the generator’s
runtime dependencies to Roslyn.
Because the second reference is a normal assembly reference, the generator’s Roslyn dependencies
also become visible to the test compilation. For a multi-target test project, build the generator
against the Roslyn version that supports its API usage and is compatible with the oldest test target.
This framework is built against Roslyn 5.0 (C# 14 / .NET 10 generation), which ships net8.0 and
net9.0 package assets, so a .NET 8–.NET 10 test matrix still loads it. Compiler hosts must be
Roslyn 5.0 or later (.NET 10 SDK / Visual Studio 2026). Do not centrally pin
System.Collections.Immutable to a newer runtime version merely to make the generator load.
Write a generator
Section titled “Write a generator”Implement IIncrementalGenerator and use the framework helpers to build a pipeline:
using Microsoft.CodeAnalysis;using Purview.SourceGeneratorFramework.Helpers;using Purview.SourceGeneratorFramework.Models;
[Generator]public sealed class MyGenerator : IIncrementalGenerator{ static readonly TypeIdentity AttributeType = new("MyAttribute", "MyNamespace");
public void Initialize(IncrementalGeneratorInitializationContext context) { var contextProvider = IncrementalPipeline.DefaultGenerationContextValueProvider<MyGenerator>(context);
var targets = IncrementalPipeline.ForAttributeWithMetadataName( context, AttributeType, static (ctx, ct) => ctx.TargetSymbol.Name );
context.RegisterSourceOutput( targets.CombineWithContext(contextProvider), static (spc, pair) => { var (name, generationContext) = pair; var writer = generationContext.CreateCodeWriter(); writer.AutoGeneratedHeader(); writer.FileScopedNamespace("MyNamespace"); writer.Class( name, TypeDeclarationAccessibility.Public, options => options with { IsStatic = true }, body => body.Comment("generated content") );
spc.AddSource($"{name}.g.cs", writer.ToString()); } ); }}See the SourceGeneratorFramework.ExampleGenerator
reference implementation for a complete end-to-end sample, and
SourceGeneratorFramework.ExampleGenerator.CodeFixers
for a companion code-fix sample.
Test the generator
Section titled “Test the generator”Reference the testing package and run the generator against a snippet of C#:
dotnet add package Purview.SourceGeneratorFramework.Testingusing Purview.SourceGeneratorFramework.Testing;
public class MyGeneratorTests{ [Test] public async Task GeneratesExpectedSource() { var source = """ [MyNamespace.MyAttribute] public partial class MyClass { } """;
var runner = new SourceGeneratorTestRunner<MyGenerator>(); var result = await runner.RunAsync(source);
result.AssertNoCompilationErrors(); var generated = result.AssertSingleGeneratedSource(); }}Use the TUnit integration for ready-made test base classes and fluent assertions:
dotnet add package Purview.SourceGeneratorFramework.Testing.TUnit