FSharp.Text.TypedTemplateProvider
1.1.0
dotnet add package FSharp.Text.TypedTemplateProvider --version 1.1.0
NuGet\Install-Package FSharp.Text.TypedTemplateProvider -Version 1.1.0
<PackageReference Include="FSharp.Text.TypedTemplateProvider" Version="1.1.0" />
<PackageVersion Include="FSharp.Text.TypedTemplateProvider" Version="1.1.0" />
<PackageReference Include="FSharp.Text.TypedTemplateProvider" />
paket add FSharp.Text.TypedTemplateProvider --version 1.1.0
#r "nuget: FSharp.Text.TypedTemplateProvider, 1.1.0"
#:package FSharp.Text.TypedTemplateProvider@1.1.0
#addin nuget:?package=FSharp.Text.TypedTemplateProvider&version=1.1.0
#tool nuget:?package=FSharp.Text.TypedTemplateProvider&version=1.1.0
TypedTemplateProvider (aka "Trulla")
...an F# strongly typed text template provider!
Status: Still experimental
#r "nuget: FSharp.Text.TypedTemplateProvider, 0.0.0-alpha01"
open FSharp.Text.TypedTemplateProvider
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(false, "Order 1")
Tmpl.order(true, "Order 2")
],
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)
---
The approach of FSharp.Text.TypedTemplateProvider 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
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) Rendering.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.1.0 | 527 | 3/15/2023 | |
| 1.0.1 | 522 | 1/14/2023 | |
| 1.0.0 | 521 | 12/27/2022 | |
| 0.0.0-alpha05 | 332 | 12/22/2022 | |
| 0.0.0-alpha03 | 310 | 12/22/2022 | |
| 0.0.0-alpha02 | 319 | 12/21/2022 | |
| 0.0.0-alpha01 | 324 | 12/21/2022 |
1.0.0
- initial
1.0.1
- #5: Don't ref FSharp.Core 7
- #6: Stable ordering of ctor params