https://github.com/skarllot/sourcegenerators
Provides utility functions and helpers to aid in writing source files for source generators using high-performance writer and string interpolations
https://github.com/skarllot/sourcegenerators
codewriter generator interpolation performance source span template
Last synced: 25 days ago
JSON representation
Provides utility functions and helpers to aid in writing source files for source generators using high-performance writer and string interpolations
- Host: GitHub
- URL: https://github.com/skarllot/sourcegenerators
- Owner: skarllot
- License: mit
- Created: 2023-12-10T21:33:54.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2026-03-24T12:39:54.000Z (about 1 month ago)
- Last Synced: 2026-03-25T15:07:46.730Z (about 1 month ago)
- Topics: codewriter, generator, interpolation, performance, source, span, template
- Language: C#
- Homepage:
- Size: 3.99 MB
- Stars: 3
- Watchers: 2
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Codeowners: .github/CODEOWNERS
- Security: SECURITY.md
Awesome Lists containing this project
README
SourceGenerators
[](https://github.com/skarllot/SourceGenerators/actions)
[](https://codecov.io/gh/skarllot/SourceGenerators)
[](https://securityscorecards.dev/viewer/?uri=github.com/skarllot/SourceGenerators)
[](https://raw.githubusercontent.com/skarllot/SourceGenerators/main/LICENSE)
_Provides utility functions and helpers to aid in writing source files for source generators using high-performance writer and string interpolations_
[🏃 Quickstart](#quickstart) | [📗 Guide](#guide) | [📦 NuGet](#nuget-packages)
A high-performance source text writer for .NET incremental source generators. Write generated source code using plain
strings or C# string interpolations with automatic indentation support.
## NuGet Packages
* [](https://www.nuget.org/packages/Raiqub.Generators.InterpolationCodeWriter/) **Raiqub.Generators.InterpolationCodeWriter**: provides a compiled library with `SourceTextWriter` for writing source code
* [](https://www.nuget.org/packages/Raiqub.Generators.InterpolationCodeWriter.CSharp/) **Raiqub.Generators.InterpolationCodeWriter.CSharp**: provides a compiled library with `CodeWriterDispatcher` and extensions for Roslyn source generators
* [](https://www.nuget.org/packages/Raiqub.Generators.InterpolationCodeWriter.CSharp.Sources/) **Raiqub.Generators.InterpolationCodeWriter.CSharp.Sources**: provides source files that are embedded into your project (no runtime dependency)
## Compatibility
The compiled libraries target .NET Standard 2.0, .NET 8, and .NET 10. The source files package requires at least the
.NET 6.0 SDK, but you can target earlier frameworks.
## Quickstart
Add the source files package to your source generator project:
```shell
dotnet add package Raiqub.Generators.InterpolationCodeWriter.CSharp.Sources
```
Then implement the `ICodeWriter` interface to define your code writer:
```csharp
public class MyWriter : ICodeWriter
{
public bool CanGenerateFor(MyModel model) => model.Properties.Count > 0;
public string GetFileName(MyModel model) => $"{model.Namespace ?? "_"}.{model.Name}Extensions.g.cs";
public void Write(SourceTextWriter writer, MyModel model)
{
writer.WriteLine($"namespace {model.Namespace};");
writer.WriteLine();
writer.WriteLine($"public static partial class {model.Name}Extensions");
writer.WriteLine("{");
writer.PushIndent();
// Write members using string interpolation...
writer.PopIndent();
writer.WriteLine("}");
}
}
```
## Guide
### SourceTextWriter
`SourceTextWriter` is a high-performance text writer built on `StringBuilder` with automatic indentation support. It accepts plain strings and C# string interpolations through a custom `InterpolatedStringHandler`.
```csharp
var writer = new SourceTextWriter();
writer.WriteLine("using System;");
writer.WriteLine();
writer.WriteLine($"namespace {ns};");
writer.WriteLine();
writer.WriteLine($"public class {className}");
writer.WriteLine("{");
writer.PushIndent();
writer.WriteLine($"public string Name {{ get; set; }}");
writer.PopIndent();
writer.WriteLine("}");
string result = writer.ToString();
```
Key features:
- **Automatic indentation**: Use `PushIndent()` / `PopIndent()` to manage indentation levels (4 spaces per level by default)
- **String interpolation support**: Write code using `$"..."` syntax directly
- **Culture-invariant formatting**: Numbers and other values are formatted using `InvariantCulture` by default
- **Configurable**: Customize line endings, indentation size, and format provider
### TextSegment
`TextSegment` is an [interpolated string handler](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/interpolated-string-handler) that captures the parts of an interpolated string for later use. It lets you compose reusable text fragments and embed them directly inside a `writer.Write($"...")` call.
**Direct assignment** from an interpolated string:
```csharp
TextSegment typeName = $"{namespaceName}.{className}";
writer.WriteLine($"// Generated type: {typeName}");
```
**Returning segments from helper methods** keeps complex formatting out of the main writer loop:
```csharp
private static TextSegment FormatTypeRef(string ns, string name) =>
$"{ns}.{name}";
// Segments are embedded as holes — no intermediate string allocation
writer.WriteLine($"[global::{FormatTypeRef("System", "Serializable")}]");
writer.WriteLine($"public partial class {className}");
```
**`TextSegment.Create`** provides extra options such as appending a line terminator or supplying a custom `IFormatProvider`:
```csharp
// Append a newline after the segment is written
TextSegment line = TextSegment.Create($"public {returnType} {methodName}();", appendLine: true);
line.WriteTo(writer);
```
### ICodeWriter / ICodeWriter<T>
`ICodeWriter` defines a stateless code writer that generates source code. `ICodeWriter` extends it with model-based generation:
- `CanGenerateFor(T model)` - determines if code should be generated for the given model
- `GetFileName(T model)` - returns the file name for the generated source
- `Write(SourceTextWriter writer, T model)` - writes the source code using the provided writer and model
Implementations should be stateless to ensure thread-safety in source generator contexts.
### CodeWriterDispatcher
`CodeWriterDispatcher` dispatches source generation across multiple code writers. It is stateless and safe to store as a static field:
```csharp
private static readonly CodeWriterDispatcher s_dispatcher =
new([new MyWriter1(), new MyWriter2()]);
```
Then call `GenerateSources` to generate source files using the `SourceProductionContext`:
```csharp
private static void Emit(
SourceProductionContext context,
ImmutableArray types)
{
s_dispatcher.GenerateSources(types, context);
}
```
An optional exception handler can be provided to report diagnostics instead of throwing:
```csharp
private static readonly CodeWriterDispatcher s_dispatcher =
new(
(ex, model) => Diagnostic.Create(...),
new MyWriter1(), new MyWriter2());
```
## Advanced Configuration
### Disabling Built-in Polyfills
The `CSharp.Sources` package embeds polyfill types (such as `SpanExtensions`, `SpanLineEnumerator`, and `StringBuilderMemory`) to support targeting .NET Standard 2.0. If your project already provides these types — for example, via the [PolyFill](https://www.nuget.org/packages/PolyFill) library — you can suppress the embedded polyfills to avoid duplicate type definition errors.
Add the `NO_RAIQUB_SOURCEGENERATORS_POLYFILL` compiler constant to your project file:
```xml
$(DefineConstants);NO_RAIQUB_SOURCEGENERATORS_POLYFILL
```
This flag has no effect on the compiled library packages (`InterpolationCodeWriter` and `InterpolationCodeWriter.CSharp`).
## Contributing
If something is not working for you or if you think that the source file
should change, feel free to create an issue or Pull Request.
I will be happy to discuss and potentially integrate your ideas!
## License
See the [LICENSE](./LICENSE) file for details.