Cutout
![]()
Templating that costs nothing at runtime.
A source generator that renders Liquid style templates into a StringBuilder at compile time, so generated code keeps its indentation without a template engine dependency.
dotnet add package Cutout
Why?
A source generator has to emit source code as a string, and that string has to keep its indentation. The two usual answers each cost something:
IndentedTextWriteris fast, but the template becomes a wall ofWriteLinecalls- a template engine reads well, but it runs at runtime, and every generated file pays for it
Cutout renders the template at compile time. The template stays readable and the
generated code is a straight line of builder.Append calls.
This template,
[Cutout.Template("{% if product == \"Awesome Shoes\" %} These shoes are awesome! {% else %} These shoes are not awesome! {% end %}")]
public static partial void Test(this StringBuilder builder, string product);
produces this method,
internal static partial void Test(this StringBuilder builder, string product)
{
if ( product == "Awesome Shoes" )
{
builder.Append(@" These shoes are awesome! ");
}
else
{
builder.Append(@" These shoes are not awesome! ");
}
}
There is no template engine at runtime; the code above is what runs.
What it does not do
- It is not a runtime template engine. Rendering happens at compile time, so a template cannot be read from a file or built at runtime
- Templates must be compile-time constants: a
conststring or a literal in the attribute - It is not full Liquid. Every block closes with
{% end %}, there are no Liquid filters, and the expressions are C# expressions - Templates have to be in the compilation unit that uses them; the generator does not render templates from another project
See also
- Getting Started - add the generator to a project
- Template Definition - syntax and the deviations from Liquid
- Analyser Rules - what the analyser catches