Skip to content

jrconradt/Templar.Net

Repository files navigation

Templar

CI .NET License

Indentation-aware template engine for C# codegen — multi-line values inherit the placeholder's column, trim/AOT-safe, zero dependencies.

The Problem

Standard template engines break indentation when substituting multi-line values:

// Template:          // Output (broken):
class Foo             class Foo
{                     {
    {{ body }}            public void A()
}                     {
                          // ...
                      }
                      }

Templar's Solution

Continuation lines are padded to the placeholder's column:

// Template:          // Output (correct):
class Foo             class Foo
{                     {
    {{ body }}            public void A()
}                         {
                              // ...
                          }
                      }

This works at arbitrary nesting depths and composes — inner templates render into outer templates with indentation preserved across boundaries.

Quick Start

Install from NuGet:

dotnet add package Templar.Net

Given a template file Templates/Calculator.tpl:

public static class {{ name }}
{
    {{ body }}
}

Load it, fill it, render it:

using Templar.Rendering;

var set = new TemplateSet().AddDirectory("Templates");
var template = set.Get("Calculator");

template["name"] = "Calculator";
template["body"] = "public int Add(int a, int b)\n{\n    return a + b;\n}";

Console.WriteLine(template.Render());

The multi-line body is injected at the {{ body }} column, so the rendered method body lines up one indent inside the class — no manual padding.

Syntax

Form Example Effect
Variable {{ name }} Replaced with value (empty if unset)
Filter {{ name | pascal }} Value transformed by filter
Comment {{# ignored }} Stripped entirely from output
Conditional {{? flag }}…{{?}} Body rendered when flag is truthy
Else branch {{? flag }}…{{?else}}…{{?}} Second arm rendered when flag is falsy
Negation {{?!flag }}…{{?}} Body rendered when flag is falsy
Escape \{{ · \}} · \\ Literal {{, }}, \

Variable and filter names are case-insensitive. A conditional tests one variable by name — null, "", false, and an empty IEnumerable are falsy; everything else is truthy. Conditional tags are inline: keep {{? }}{{?}} on the same line as the text they guard. A line containing only value placeholders that all render empty is dropped entirely, trailing newline included.

Built-in Filters

Filter Input Output
upper hello world HELLO WORLD
lower Hello World hello world
pascal hello_world HelloWorld
camel hello_world helloWorld

Custom filters: template.AddFilter("myFilter", val => ...).

Composition

The Compositor base class lets a class be a template: define Structure (the template text) and Templar auto-binds every readable instance property to a template variable matching the property name. The built-in CSharpFile preset provides a five-section structure for generating .cs files: header, pragmas, usings, file-scoped namespace, and body.

using Templar.Presets;

var file = new CSharpFile
{
    Namespace = "MyApp.Generated",
    Usings    = new[] { "System", "System.Linq" },
    Body      = "public sealed class Foo;"
};

string output = file.Render();

See _docs/composition.md for the full pattern, including [TemplateBind], [TemplateIgnore], inheritance, and overriding Populate.

Sequences

A Sequence composes other values, rendering and joining them by a separator with the placeholder's indentation preserved on every line of every item. Construct one with new Sequence(items, separator), or use a built-in factory — Sequence.Lines (newline), Sequence.BlankLines (blank line between items), or Sequence.CommaList (, ); any plain IEnumerable<IComposable> value is joined by newline. CSharpFile uses one internally: its UsingsBlock is Sequence.Lines over Using compositors. Sequence, like Compositor, implements IComposable — the engine's composition primitive — so the two compose interchangeably.

Render Options

RenderOptions, applied via template.WithOptions(...) or TemplateSet.WithOptions(...), controls rendering:

Option Default Effect
IndentString four spaces Unit of indentation for nested substitution
Newline \n Output line ending; injected \r\n / \r are normalized to it
StrictUndefined false When true, rendering a variable that was never set throws TemplateRenderException instead of emitting empty

Templar is trim- and AOT-safe (IsTrimmable / IsAotCompatible), so it can be embedded in published, trimmed, or NativeAOT code generators.

Documentation

Long-form docs live in _docs/:

Page Covers
syntax.md Placeholder, filter, comment, and indentation rules.
templates.md Constructing, filling, and rendering a single template.
composition.md Compositor, Sequence, attributes, the CSharpFile preset.
integration.md TemplateSet, embedded resources, filter/options propagation, generators.
ui.md Templar.UI — server-rendered HTML/XML/SVG component toolkit with auto-escaping.

Build & Test

Requires .NET 10 SDK. Zero external dependencies.

dotnet build Templar.slnx
dotnet test Templar.slnx

Status

Active development; the core rendering API is stable, while the preset and Templar.UI surface are still evolving.

License

Apache-2.0. Copyright 2026 Infalligence Labs LLC — see LICENSE.

About

Indentation-aware C# template engine for codegen — multi-line values inherit the placeholder's column; trim/AOT-safe, zero dependencies.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors