Skip to content

Deepstaging.Roslyn.Scriban

Scriban template infrastructure for Roslyn incremental source generators.

What is this?

This library provides a convenient way to use Scriban templates in Roslyn source generators. Instead of building C# strings manually, you write .scriban-cs templates and render them with model objects.

Installation

dotnet add package Deepstaging.Roslyn.Scriban

Quick Start

1. Create a template

Add a .scriban-cs file as an embedded resource:

// {{ model.name }}.g.cs
// <auto-generated/>
#nullable enable

namespace {{ model.namespace }};

public partial class {{ model.name }}
{
{{~ for prop in model.properties ~}}
    public {{ prop.type }} {{ prop.name }} { get; set; }
{{~ end ~}}
}

2. Set up the template name factory

public class MyGenerator : IIncrementalGenerator
{
    private static readonly Func<string, TemplateName> Named = 
        TemplateName.ForGenerator<MyGenerator>();

    // ...
}

3. Render and add to output

context.AddFromTemplate(
    Named("MyTemplate.scriban-cs"),
    hintName: $"{model.Name}.g.cs",
    context: model);

API Reference

TemplateName

Identifies a template by its embedded resource name and assembly:

// Create a factory for your generator's namespace
var Named = TemplateName.ForGenerator<MyGenerator>();

// Creates: "MyNamespace.Templates.MyTemplate.scriban-cs"
var templateName = Named("MyTemplate.scriban-cs");

Template

Loads and renders Scriban templates from embedded resources:

// Render directly
var result = Template.RenderTemplate(templateName, model);

switch (result)
{
    case RenderResult.Success success:
        string code = success.Text;
        break;
    case RenderResult.Failure failure:
        Diagnostic error = failure.Diagnostic;
        break;
}

Context Extensions

Extension methods for generator contexts:

// In SourceProductionContext (main generation phase)
context.AddFromTemplate(
    Named("Template.scriban-cs"),
    hintName,
    context: model,
    diagnostics: optionalDiagnosticList,
    format: true);  // Optional: format with Roslyn

// In IncrementalGeneratorPostInitializationContext (static output)
context.AddFromTemplate(
    Named("StaticTemplate.scriban-cs"),
    hintName,
    context: model);

Template Conventions

File Extension

Templates use .scriban-cs extension and are embedded resources:

<ItemGroup>
  <EmbeddedResource Include="Templates\*.scriban-cs" />
</ItemGroup>

Directory Structure

Templates live in a Templates/ directory next to your generator:

MyProject/
├── MyGenerator.cs
└── Templates/
    ├── Class.scriban-cs
    └── Interface.scriban-cs

Snake Case Access

Model properties are automatically accessible in snake_case:

// C# model
record MyModel(string FullName, int MaxRetries);
{{ model.full_name }}     # Accesses FullName
{{ model.max_retries }}   # Accesses MaxRetries

Performance

Templates are cached at two levels:

  1. Text cache - Embedded resource text is cached by (Assembly, ResourceName)
  2. Parse cache - Parsed Scriban templates are cached by template text

This avoids repeated I/O and parsing during incremental generation, which is critical for IDE responsiveness.

Error Handling

Template errors produce Roslyn diagnostics with ID DEEPCORE001:

Scenario Message Format
Parse error ParsingError occurred while rendering a template: {errors}
Render error {ExceptionType} occurred while rendering a template: {message}

Errors are reported via SourceProductionContext.ReportDiagnostic() so they appear in the IDE.