Deepstaging.Roslyn¶
Roslyn's missing standard library. Fluent queries, safe projections, code generation, analyzer base classes, and snapshot testing — everything you need to build production source generators without fighting the compiler.
Why Deepstaging.Roslyn? Get Started
-
Find Symbols, Not Syntax Trees
Fluent queries replace raw
GetMembers().OfType<>()chains. Filter by visibility, modifiers, attributes, names, return types — and get back actualISymbolobjects you can use with any Roslyn API. -
No More Null Checks
OptionalSymbol<T>andValidAttributewrap Roslyn's nullable minefield in a safe-access pattern. Extract attribute arguments, named args, and type info without ever writing?.chains or null guards. -
Generate Code That Reads Like Code
TypeBuilder,MethodBuilder, andPropertyBuildercompose entire classes with a fluent API. Parse complex signatures from strings or build them piece by piece — either way you get validCompilationUnitSyntax. -
One-Method Analyzers
TypeAnalyzer<T>,MethodAnalyzer<T>,FieldAnalyzer<T>— override a single boolean method. The base class handles registration, symbol matching, diagnostic creation, and concurrent execution. -
Code Fixes in 5 Lines
AddPartialModifierAction,AddModifierAction,ModifyPropsFileAction— pre-built actions for common fixes. Pair with analyzers using[CodeFix("DIAG001")]and ship one-click repairs. -
Test Everything, Mock Nothing
RoslynTestBasegives you generator snapshot tests, analyzer diagnostic assertions, code fix verification, and template rendering — all with consistent, readable APIs. No manual compilation setup.
What It Looks Like¶
Find → Project → Emit¶
// Query: find types with your attribute
var models = context.ForAttribute<AutoNotifyAttribute>()
.Map(static (ctx, _) => ctx.TargetSymbol
.AsValidNamedType()
.QueryAutoNotify());
// Emit: generate a class from the model
context.RegisterSourceOutput(models, static (ctx, model) => TypeBuilder
.Class(model.TypeName)
.AsPartial()
.InNamespace(model.Namespace)
.ImplementsINotifyPropertyChanged()
.WithEach(model.Fields, (type, field) => type
.AddProperty(field.PropertyName, field.TypeName, p => p
.WithGetter(b => b.AddStatement($"return {field.FieldName}"))
.WithSetter(b => b
.AddStatement($"{field.FieldName} = value")
.AddStatement($"OnPropertyChanged()"))))
.Emit()
.AddSourceTo(ctx, HintName.From(model.Namespace, model.TypeName)));
One-Method Analyzers¶
[Reports("RK001", "Type with [AutoNotify] must be partial",
Category = "Usage", Severity = DiagnosticSeverity.Error)]
public sealed class MustBePartialAnalyzer : TypeAnalyzer<AutoNotifyAttribute>
{
protected override bool ShouldReport(ValidSymbol<INamedTypeSymbol> type)
=> !type.IsPartial;
}
Pipeline Models That Just Work¶
// [PipelineModel] generates Equals/GetHashCode for incremental caching
[PipelineModel]
internal sealed record AutoNotifyModel(
string Namespace,
string TypeName,
EquatableArray<FieldModel> Fields);
Install¶
Packages¶
| Package | Purpose |
|---|---|
Deepstaging.Roslyn |
Core toolkit — Queries, Projections, Emit, Analyzers, Generators, Code Fixes, Scriban |
Deepstaging.Roslyn.Testing |
Test utilities for generators, analyzers, and code fixes |
Deepstaging.Roslyn.LanguageExt |
LanguageExt integration — Eff lifting, expressions, types |
Learn¶
-
Build a complete
[AutoNotify]generator — attribute, query, emit, analyzer, code fix, and tests — in one sitting. -
Trace a real feature (
[StrongId]) across all five layers from the Deepstaging source. -
dotnet new roslynkitscaffolds a full five-layer solution with CI, docs, and packaging. -
Project organization, projection patterns, generator architecture, analyzer base classes, code fix helpers, and testing strategies.
Philosophy¶
This is utility code, not a framework. It should feel like the standard library Roslyn forgot to ship.
- Roslyn in, Roslyn out.
.GetAll()returns actualISymbolobjects..Emit()returnsCompilationUnitSyntax. No wrappers that hide the platform. - Reading and writing are symmetric.
TypeQueryfinds types,TypeBuildercreates them. Same mental model both ways. - Composition over inheritance. Fluent APIs compose — chain what you need, skip what you don't. No deep class hierarchies to learn.
Built With¶
Deepstaging — a declarative application framework — is built entirely on this toolkit. 6 generators, 50+ analyzers, 20+ code fixes, all using the patterns described in these docs.
License¶
RPL-1.5 (Reciprocal Public License) — Real reciprocity, no loopholes.
You can use this code, modify it, and share it freely. But when you deploy it — internally or externally, as a service or within your company — you share your improvements back under the same license.
Why? We believe if you benefit from this code, the community should benefit from your improvements. That's the deal we think is fair.
Personal research and experimentation? No obligations. Go learn, explore, and build.
See LICENSE for the full legal text.