Trulla 1.3.0-preview8
See the version list below for details.
dotnet add package Trulla --version 1.3.0-preview8
NuGet\Install-Package Trulla -Version 1.3.0-preview8
<PackageReference Include="Trulla" Version="1.3.0-preview8" />
<PackageVersion Include="Trulla" Version="1.3.0-preview8" />
<PackageReference Include="Trulla" />
paket add Trulla --version 1.3.0-preview8
#r "nuget: Trulla, 1.3.0-preview8"
#:package Trulla@1.3.0-preview8
#addin nuget:?package=Trulla&version=1.3.0-preview8&prerelease
#tool nuget:?package=Trulla&version=1.3.0-preview8&prerelease
Trulla Templates
...an F# strongly typed text template provider!
Status: Stable
#r "nuget: Trulla"
open Trulla
let [<Literal>] TestTemplate = """
Hello {{user.name}}, how are you?
Your Orders
===
{{for order in orders|---}}
ID: {{order.id}}
({{if order.isActive}}active{{else}}inactive{{end}})
{{end}}
"""
// All types required by the given template
// are infered and provided:
type Tmpl = Template<TestTemplate>
// Instanciate a typed model for the tempalte.
let templateModel =
Tmpl.Root(
[
Tmpl.order("Order 1", false)
Tmpl.order("Order 2", true)
Tmpl.order("Order 3", false)
],
Tmpl.user("Hans"))
// Render and print it:
Tmpl.Render(templateModel) |> printfn "%s"
This will print:
Hello Hans, how are you?
Your Orders
===
ID: Order 1
(inactive)
---
ID: Order 2
(active)
---
ID: Order 3
(inactive)
The approach of Trulla is:
- Provide a text template with:
- template parameters
- iterations
- conditionals
- A model type is infered from a given template.
- An instance of the model is provided by the user for rendering the final template.
Limitations (current)
- The model will only contain fields of type
- list
- string (for template holes)
- bool
- There are currently no partials supported
Template Syntax
Have a look at the tests for more samples!
for loops (with separator)
- This will render 'abc' for given chars = ["a"; "b"; "c"]:
{{for c in chars}}{{c}}{{end}}
- With a given separator between items, this will render 'a;b;c' for given chars = ["a"; "b"; "c"]:
{{for x in numbers|;}}{{x.id}}{{end}}
if/else
- This will print "Order is active." or "Order is closed." depending on the value of order.isActive:
- The
elsepart is optional.
Order is {{if order.isActive}}active{{else}}closed{{end}}.
Implementation Notes
The implementation of the tempalte provider might be interesting, because it contains (in a simple form) the building blocks that are required for a programming language. It has:
A parser Parsing.fs implemented with FParsec. The parser output is a sequence of tokens:
type Token =
| Text of string
| Hole of PVal<MemberToken>
| For of ident: PVal<string> * exp: PVal<MemberToken>
| If of PVal<MemberToken>
| Else
| End
and MemberToken =
| AccessToken of {| instanceExp: PVal<MemberToken>; memberName: string |}
| IdentToken of string
An untyped AST Ast.fs that gets constructed from the parsed token sequence:
type TVar =
| Root
| TVar of int
type private BindingContext = Map<string, TVar>
type TVal<'a> =
{
range: Range
tvar: TVar
bindingContext: BindingContext
value: 'a
}
override this.ToString() = sprintf "(%A)%A" this.range this.value
type TExp =
| Text of string
| Hole of TVal<MemberExp>
| For of ident: TVal<string> * exp: TVal<MemberExp> * body: TExp list
| If of cond: TVal<MemberExp> * body: TExp list
| Else of cond: TVal<MemberExp> * body: TExp list
and Body = BindingContext * TExp list
and MemberExp =
| AccessExp of {| instanceExp: TVal<MemberExp>; memberName: string |}
| IdentExp of string
type Typ =
| Mono of string
| Poly of name: string * typParam: Typ
| Field of Field
| Record of TVar
| Var of TVar
and Field =
{
name: string
typ: Typ
}
A solver Solver.fs that types records and identifiers of the AST
type RecordDef =
{
id: TVar
fields: Field list
name: string
}
A generator (renderer) ReflectionRenderer.fs that transforms all the previous into the final string.
TODOs
- Shadowing (Explanation)
- Wildcards in bindings
- The begin and end character sequence for template expressions are configurable, and there is no way escaping them. Choose an appropriate sequence of characters that won't occur in your template.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- FParsec (>= 1.1.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.4.2 | 4,001 | 10/20/2023 |
| 1.4.1 | 227 | 10/18/2023 |
| 1.4.0-preview01 | 176 | 10/17/2023 |
| 1.3.0 | 206 | 9/18/2023 |
| 1.3.0-preview9 | 183 | 9/17/2023 |
| 1.3.0-preview8 | 174 | 9/17/2023 |
| 1.3.0-preview7 | 170 | 9/15/2023 |
| 1.3.0-preview6 | 181 | 9/15/2023 |
| 1.3.0-preview5 | 173 | 9/15/2023 |
| 1.3.0-preview4 | 173 | 9/15/2023 |
| 1.3.0-preview2 | 1,247 | 9/15/2023 |
| 1.3.0-preview18 | 136 | 9/18/2023 |
| 1.3.0-preview17 | 164 | 9/18/2023 |
| 1.3.0-preview16 | 149 | 9/18/2023 |
| 1.3.0-preview15 | 143 | 9/18/2023 |
| 1.3.0-preview14 | 157 | 9/18/2023 |
| 1.3.0-preview13 | 152 | 9/18/2023 |
| 1.3.0-preview12 | 156 | 9/18/2023 |
| 1.3.0-preview11 | 171 | 9/17/2023 |
| 1.3.0-preview10 | 176 | 9/17/2023 |
| 1.3.0-preview1 | 176 | 9/15/2023 |
| 1.2.1 | 202 | 9/13/2023 |
| 1.1.1 | 269 | 4/24/2023 |
| 1.1.0 | 256 | 4/24/2023 |
1.2.1
- Added optional separator to `for` loop
1.1.1
- Removed "experimental" notice
1.1.0
- Revisiting / renaming to "Trulla"
1.0.1
#5: Don't ref FSharp.Core 7
#6: Stable ordering of ctor params
1.0.0
Initial publish.