diff --git a/src/TextTemplate/Template.cs b/src/TextTemplate/Template.cs
new file mode 100644
index 0000000..a4ed0fd
--- /dev/null
+++ b/src/TextTemplate/Template.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using Antlr4.Runtime;
+
+namespace TextTemplate;
+
+///
+/// Represents a text template similar to Go's template.Template.
+///
+public class Template
+{
+ private string _templateString = string.Empty;
+
+ ///
+ /// The template name.
+ ///
+ public string Name { get; }
+
+ private Template(string name)
+ {
+ Name = name;
+ }
+
+ ///
+ /// Creates a new Template with the given name.
+ ///
+ public static Template New(string name) => new(name);
+
+ ///
+ /// Parses the supplied template string and returns the Template instance.
+ ///
+ public Template Parse(string templateString)
+ {
+ if (templateString == null) throw new ArgumentNullException(nameof(templateString));
+ // Validate using the TemplateEngine so parsing rules remain consistent.
+ TemplateEngine.Validate(templateString);
+ _templateString = templateString;
+ return this;
+ }
+
+ ///
+ /// Reads the given files, combines their contents, and parses the result.
+ ///
+ public Template ParseFiles(params string[] filenames)
+ {
+ if (filenames == null) throw new ArgumentNullException(nameof(filenames));
+ var sb = new StringBuilder();
+ foreach (var file in filenames)
+ {
+ sb.Append(File.ReadAllText(file));
+ }
+ return Parse(sb.ToString());
+ }
+
+ ///
+ /// Executes the template using the provided dictionary.
+ ///
+ public string Execute(IDictionary data)
+ {
+ return TemplateEngine.Process(_templateString, data);
+ }
+
+ ///
+ /// Executes the template using the public properties of .
+ ///
+ public string Execute(T model)
+ {
+ return TemplateEngine.Process(_templateString, model);
+ }
+
+}
diff --git a/src/TextTemplate/TemplateEngine.cs b/src/TextTemplate/TemplateEngine.cs
index 11d2cf0..d72dd81 100644
--- a/src/TextTemplate/TemplateEngine.cs
+++ b/src/TextTemplate/TemplateEngine.cs
@@ -24,7 +24,7 @@ public static string Process(string templateString, IDictionary
{
templateString = PreprocessWhitespace(templateString);
templateString = PreprocessComments(templateString);
- AntlrInputStream inputStream = new(templateString);
+ var inputStream = new AntlrInputStream(templateString);
var lexer = new GoTextTemplateLexer(inputStream);
var tokens = new CommonTokenStream(lexer);
var parser = new GoTextTemplateParser(tokens);
@@ -35,6 +35,21 @@ public static string Process(string templateString, IDictionary
return visitor.Visit(tree);
}
+ ///
+ /// Parses to ensure it contains valid syntax.
+ ///
+ public static void Validate(string templateString)
+ {
+ if (templateString == null) throw new ArgumentNullException(nameof(templateString));
+ templateString = PreprocessWhitespace(templateString);
+ templateString = PreprocessComments(templateString);
+ var inputStream = new AntlrInputStream(templateString);
+ var lexer = new GoTextTemplateLexer(inputStream);
+ var tokens = new CommonTokenStream(lexer);
+ var parser = new GoTextTemplateParser(tokens);
+ parser.template();
+ }
+
///
/// Processes using the public properties
/// and fields of as template variables.
diff --git a/tests/TextTemplate.Tests/TemplateClassTests.cs b/tests/TextTemplate.Tests/TemplateClassTests.cs
new file mode 100644
index 0000000..9cdeef4
--- /dev/null
+++ b/tests/TextTemplate.Tests/TemplateClassTests.cs
@@ -0,0 +1,41 @@
+using Shouldly;
+using TextTemplate;
+using Xunit;
+using System.IO;
+
+namespace TextTemplate.Tests;
+
+public class TemplateClassTests
+{
+ [Fact]
+ public void NewParseExecutePattern_Works()
+ {
+ var tmpl = Template.New("t").Parse("Hello {{ .Name }}! {{ range .Items }}{{ . }} {{ end }}");
+ var result = tmpl.Execute(new { Name = "Bob", Items = new[] { "a", "b" } });
+ result.ShouldBe("Hello Bob! a b ");
+ }
+
+ [Fact]
+ public void ParseFiles_ReadsAndParsesAllFiles()
+ {
+ var f1 = Path.GetTempFileName();
+ var f2 = Path.GetTempFileName();
+ var f3 = Path.GetTempFileName();
+ try
+ {
+ File.WriteAllText(f1, "{{define \"header\"}}Hello {{.Name}}{{end}}");
+ File.WriteAllText(f2, "{{define \"exclaim\"}}!{{end}}");
+ File.WriteAllText(f3, "{{template \"header\" .}}{{template \"exclaim\"}}");
+
+ var tmpl = Template.New("t").ParseFiles(f1, f2, f3);
+ var result = tmpl.Execute(new { Name = "Ann" });
+ result.ShouldBe("Hello Ann!");
+ }
+ finally
+ {
+ File.Delete(f1);
+ File.Delete(f2);
+ File.Delete(f3);
+ }
+ }
+}