diff --git a/.gitignore b/.gitignore
index e5e574e..06a2f4f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,5 @@ obj/
/packages/
riderModule.iml
/_ReSharper.Caches/\
-/.idea/
\ No newline at end of file
+/.idea/
+Htmt.sln.DotSettings.user
diff --git a/Htmt/AttributeParsers/BaseAttributeParser.cs b/Htmt/AttributeParsers/BaseAttributeParser.cs
new file mode 100644
index 0000000..556604a
--- /dev/null
+++ b/Htmt/AttributeParsers/BaseAttributeParser.cs
@@ -0,0 +1,81 @@
+using System.Globalization;
+using System.Text.RegularExpressions;
+using System.Xml;
+
+namespace Htmt.AttributeParsers;
+
+///
+/// Base class for attribute parsers that provides some common functionality.
+///
+public partial class BaseAttributeParser : IAttributeParser
+{
+ ///
+ /// XML Tag selector for finding the relevant nodes.
+ ///
+ ///
+ public virtual string XTag => throw new NotImplementedException();
+
+ ///
+ /// The entire XML document that is being parsed.
+ ///
+ public XmlDocument Xml { get; set; } = new();
+
+ ///
+ /// Templating data.
+ ///
+ public Dictionary Data { get; set; } = new();
+
+ ///
+ /// List of expression modifiers.
+ ///
+ public IExpressionModifier[] ExpressionModifiers { get; set; } = [];
+
+ [GeneratedRegex(@"(?\{.*?\})")]
+ private static partial Regex WholeKeyRegex();
+
+ ///
+ /// Parser the expression where it replaces variables with their data, and applies
+ /// expression modifiers.
+ ///
+ ///
+ /// Returns the parsed expression as a string.
+ protected string ParseExpression(string str)
+ {
+ var matches = WholeKeyRegex().Matches(str).Select(x => x.Groups["name"].Value).ToArray();
+
+ foreach (var match in matches)
+ {
+ var strippedName = match[1..^1];
+ var expressionModifierParser = new ExpressionModifierParser { Data = Data, ExpressionModifiers = ExpressionModifiers };
+ var value = expressionModifierParser.Parse(strippedName);
+
+ if (value != null)
+ {
+ str = value switch
+ {
+ string s => str.Replace(match, s),
+ int i => str.Replace(match, i.ToString()),
+ double d => str.Replace(match, d.ToString(CultureInfo.CurrentCulture)),
+ bool b => str.Replace(match, b.ToString()),
+ _ => str.Replace(match, value.ToString()),
+ };
+ }
+ else
+ {
+ str = str.Replace(match, "");
+ }
+ }
+
+ return str;
+ }
+
+ ///
+ /// A method that is called to parse the XML nodes.
+ ///
+ ///
+ ///
+ public virtual void Parse(XmlNodeList? nodes)
+ {
+ throw new NotImplementedException();
+ }
+}
\ No newline at end of file
diff --git a/Htmt/AttributeParsers/ForAttributeParser.cs b/Htmt/AttributeParsers/ForAttributeParser.cs
index ddf37ff..9739dcc 100644
--- a/Htmt/AttributeParsers/ForAttributeParser.cs
+++ b/Htmt/AttributeParsers/ForAttributeParser.cs
@@ -2,16 +2,19 @@
namespace Htmt.AttributeParsers;
-public class ForAttributeParser : IAttributeParser
+///
+/// A parser for the x:for attribute.
+///
+public class ForAttributeParser : BaseAttributeParser
{
- public string XTag => "//*[@x:for]";
-
- public void Parse(XmlDocument xml, Dictionary data, XmlNodeList? nodes)
+ public override string XTag => "//*[@x:for]";
+
+ public override void Parse(XmlNodeList? nodes)
{
// No nodes found
if (nodes == null || nodes.Count == 0)
{
- return;
+ return;
}
Parallel.ForEach(nodes.Cast(), node =>
@@ -20,18 +23,18 @@ public void Parse(XmlDocument xml, Dictionary data, XmlNodeList
var collection = n.GetAttribute("x:for");
var asVar = n.GetAttribute("x:as");
-
+
n.RemoveAttribute("x:for");
n.RemoveAttribute("x:as");
- var value = Helper.FindValueByKeys(data, collection.Split('.'));
+ var value = Utils.FindValueByKeys(Data, collection.Split('.'));
if (value is not IEnumerable
", html);
}
@@ -312,7 +312,7 @@ public void TestInnerPartialAttributeParserWithData()
var data = new Dictionary { { "partial", partial }, { "name", "World" } };
var parser = new Parser { Template = template, Data = data };
var html = parser.ToHtml();
-
+
Assert.AreEqual("Hello, World!
", html);
}
@@ -324,10 +324,10 @@ public void TestInnerPartialAttributeParserWithHtmlEntities()
var data = new Dictionary { { "partial", partial } };
var parser = new Parser { Template = template, Data = data };
var html = parser.ToHtml();
-
+
Assert.AreEqual("This way →
", html);
}
-
+
[TestMethod]
public void TestOuterPartialAttributeParser()
{
@@ -336,10 +336,10 @@ public void TestOuterPartialAttributeParser()
var data = new Dictionary { { "partial", partial } };
var parser = new Parser { Template = template, Data = data };
var html = parser.ToHtml();
-
+
Assert.AreEqual("Hello, World!
", html);
}
-
+
[TestMethod]
public void TestOuterPartialAttributeParserWithData()
{
@@ -348,7 +348,7 @@ public void TestOuterPartialAttributeParserWithData()
var data = new Dictionary { { "partial", partial }, { "name", "World" } };
var parser = new Parser { Template = template, Data = data };
var html = parser.ToHtml();
-
+
Assert.AreEqual("Hello, World!
", html);
}
@@ -360,7 +360,7 @@ public void TestOuterPartialAttributeParserWithHtmlEntities()
var data = new Dictionary { { "partial", partial } };
var parser = new Parser { Template = template, Data = data };
var html = parser.ToHtml();
-
+
Assert.AreEqual("This way →
", html);
}
}
\ No newline at end of file
diff --git a/HtmtTests/ExpressionModifierTest.cs b/HtmtTests/ExpressionModifierTest.cs
new file mode 100644
index 0000000..fb233f1
--- /dev/null
+++ b/HtmtTests/ExpressionModifierTest.cs
@@ -0,0 +1,172 @@
+namespace HtmtTests;
+
+using Htmt;
+
+[TestClass]
+public class ExpressionModifierTest
+{
+ [TestMethod]
+ public void TestDateModifier()
+ {
+ const string template = "";
+ var data = new Dictionary { { "date", "2022-01-01" } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("2022
", html);
+ }
+
+ [TestMethod]
+ public void TestDateModifierWithNoArgs()
+ {
+ const string template = "";
+ var data = new Dictionary { { "date", "2022-01-01" } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("2022-01-01
", html);
+ }
+
+ [TestMethod]
+ public void TestDateModifierWithDateTimeVal()
+ {
+ const string template = "";
+ var data = new Dictionary { { "date", DateTime.Parse("2022-01-01") } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("2022
", html);
+ }
+
+ [TestMethod]
+ public void TestUppercaseModifier()
+ {
+ const string template = "";
+ var data = new Dictionary { { "text", "hello, world!" } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("HELLO, WORLD!
", html);
+ }
+
+ [TestMethod]
+ public void TestUppercaseModifierWithNull()
+ {
+ const string template = "";
+ var data = new Dictionary { { "text", null } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("", html);
+ }
+
+ [TestMethod]
+ public void TestUppercaseModifierWithInt()
+ {
+ const string template = "";
+ var data = new Dictionary { { "text", 123 } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("123
", html);
+ }
+
+ [TestMethod]
+ public void TestLowercaseModifier()
+ {
+ const string template = "";
+ var data = new Dictionary { { "text", "HELLO, WORLD!" } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("hello, world!
", html);
+ }
+
+ [TestMethod]
+ public void TestLowercaseModifierWithNull()
+ {
+ const string template = "";
+ var data = new Dictionary { { "text", null } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("", html);
+ }
+
+ [TestMethod]
+ public void TestLowercaseModifierWithInt()
+ {
+ const string template = "";
+ var data = new Dictionary { { "text", 123 } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("123
", html);
+ }
+
+ [TestMethod]
+ public void TestCapitalizeModifier()
+ {
+ const string template = "";
+ var data = new Dictionary { { "text", "hello, world!" } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("Hello, world!
", html);
+ }
+
+ [TestMethod]
+ public void TestCapitalizeModifierWithNull()
+ {
+ const string template = "";
+ var data = new Dictionary { { "text", null } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("", html);
+ }
+
+ [TestMethod]
+ public void TestCapitalizeModifierSingleChar()
+ {
+ const string template = "";
+ var data = new Dictionary { { "text", "a" } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("A
", html);
+ }
+
+ [TestMethod]
+ public void TestTruncateModifier()
+ {
+ const string template = "";
+ var data = new Dictionary { { "text", "hello, world!" } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("hello
", html);
+ }
+
+ [TestMethod]
+ public void TestTruncateModifierWithoutArgs()
+ {
+ const string template = "";
+ var data = new Dictionary { { "text", "hello, world!" } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("hello, world!
", html);
+ }
+
+ [TestMethod]
+ public void TestReverseModifier()
+ {
+ const string template = "";
+ var data = new Dictionary { { "text", "hello, world!" } };
+ var parser = new Parser { Template = template, Data = data };
+ var html = parser.ToHtml();
+
+ Assert.AreEqual("!dlrow ,olleh
", html);
+ }
+}
diff --git a/HtmtTests/ExpressionValidatorTest.cs b/HtmtTests/ExpressionValidatorTest.cs
index e65d157..45d1b27 100644
--- a/HtmtTests/ExpressionValidatorTest.cs
+++ b/HtmtTests/ExpressionValidatorTest.cs
@@ -8,9 +8,10 @@ public class ExpressionValidatorTest
[TestMethod]
public void TestSimpleOr()
{
- var returnsTrue = new ExpressionValidator("(1 is 1) or (2 is 3)").Validates(new Dictionary());
- var returnsFalse = new ExpressionValidator("(1 is 2) or (2 is 3)").Validates(new Dictionary());
-
+ var data = new Dictionary { { "test", 1 } };
+ var returnsTrue = new ExpressionBooleanValidator { Expression = "1 is 1 or 2 is 3", Data = data }.Validates();
+ var returnsFalse = new ExpressionBooleanValidator { Expression = "1 is 2 or 2 is 4", Data = data }.Validates();
+
Assert.IsTrue(returnsTrue);
Assert.IsFalse(returnsFalse);
}
@@ -18,98 +19,108 @@ public void TestSimpleOr()
[TestMethod]
public void TestIntComparisons()
{
- var returnsTrue = new ExpressionValidator("test is 1").Validates(new Dictionary() { { "test", 1 } });
- var returnsFalse = new ExpressionValidator("test is 1").Validates(new Dictionary() { { "test", 2 } });
-
+ var data = new Dictionary { { "test", 1 } };
+ var returnsTrue = new ExpressionBooleanValidator { Expression = "test is 1", Data = data }.Validates();
+ var returnsFalse = new ExpressionBooleanValidator { Expression = "test is 2", Data = data }.Validates();
+
Assert.IsTrue(returnsTrue);
Assert.IsFalse(returnsFalse);
}
-
+
[TestMethod]
public void TestDoubleComparisons()
{
- var returnsTrue = new ExpressionValidator("test is 1.1").Validates(new Dictionary() { { "test", 1.1 } });
- var returnsFalse = new ExpressionValidator("test is 1.1").Validates(new Dictionary() { { "test", 1.2 } });
+ var data = new Dictionary { { "test", 1.1 } };
+ var returnsTrue = new ExpressionBooleanValidator { Expression = "test is 1.1", Data = data }.Validates();
+ var returnsFalse = new ExpressionBooleanValidator { Expression = "test is 1.2", Data = data }.Validates();
Assert.IsTrue(returnsTrue);
Assert.IsFalse(returnsFalse);
}
-
+
[TestMethod]
public void TestFloatComparisons()
{
- var returnsTrue = new ExpressionValidator("test is 1.1").Validates(new Dictionary() { { "test", 1.1f } });
- var returnsFalse = new ExpressionValidator("test is 1.1").Validates(new Dictionary() { { "test", 1.2f } });
-
+ var data = new Dictionary { { "test", 1.1f } };
+ var returnsTrue = new ExpressionBooleanValidator { Expression = "test is 1.1", Data = data }.Validates();
+ var returnsFalse = new ExpressionBooleanValidator { Expression = "test is 1.2", Data = data }.Validates();
+
Assert.IsTrue(returnsTrue);
Assert.IsFalse(returnsFalse);
}
-
+
[TestMethod]
public void TestStringComparisons()
{
- var returnsTrue = new ExpressionValidator("test is 'test'").Validates(new Dictionary() { { "test", "test" } });
- var returnsFalse = new ExpressionValidator("test is 'test'").Validates(new Dictionary() { { "test", "test2" } });
-
+ var data = new Dictionary { { "test", "test" } };
+ var returnsTrue = new ExpressionBooleanValidator { Expression = "test is 'test'", Data = data }.Validates();
+ var returnsFalse = new ExpressionBooleanValidator { Expression = "test is 'test2'", Data = data }.Validates();
+
Assert.IsTrue(returnsTrue);
Assert.IsFalse(returnsFalse);
}
-
+
[TestMethod]
public void TestBooleanComparisons()
{
- var returnsTrue = new ExpressionValidator("test is true").Validates(new Dictionary() { { "test", true } });
- var returnsFalse = new ExpressionValidator("test is true").Validates(new Dictionary() { { "test", false } });
-
+ var data = new Dictionary { { "test", true } };
+ var returnsTrue = new ExpressionBooleanValidator { Expression = "test is true", Data = data }.Validates();
+ var returnsFalse = new ExpressionBooleanValidator { Expression = "test is false", Data = data }.Validates();
+
Assert.IsTrue(returnsTrue);
Assert.IsFalse(returnsFalse);
}
-
+
[TestMethod]
public void TestNullComparisons()
{
- var returnsTrue = new ExpressionValidator("test is null").Validates(new Dictionary() { { "test", null } });
- var returnsFalse = new ExpressionValidator("test is null").Validates(new Dictionary() { { "test", "test" } });
-
+ var data = new Dictionary { { "test", null } };
+ var returnsTrue = new ExpressionBooleanValidator { Expression = "test is null", Data = data }.Validates();
+ var returnsFalse = new ExpressionBooleanValidator { Expression = "test is not null", Data = data }.Validates();
+
Assert.IsTrue(returnsTrue);
Assert.IsFalse(returnsFalse);
}
-
+
[TestMethod]
public void TestAnd()
{
- var returnsTrue = new ExpressionValidator("(test is 1) and (test2 is 2)").Validates(new Dictionary() { { "test", 1 }, { "test2", 2 } });
- var returnsFalse = new ExpressionValidator("(test is 1) and (test2 is 2)").Validates(new Dictionary() { { "test", 1 }, { "test2", 3 } });
-
+ var data = new Dictionary { { "test", 1 }, { "test2", 2 } };
+ var returnsTrue = new ExpressionBooleanValidator { Expression = "test is 1 and test2 is 2", Data = data }.Validates();
+ var returnsFalse = new ExpressionBooleanValidator { Expression = "test is 1 and test2 is 3", Data = data }.Validates();
+
Assert.IsTrue(returnsTrue);
Assert.IsFalse(returnsFalse);
}
-
+
[TestMethod]
public void TestComplexAndExpression()
{
- var returnsTrue = new ExpressionValidator("((test is 1) and (test2 is 2)) or (test3 is 3)").Validates(new Dictionary() { { "test", 1 }, { "test2", 2 }, { "test3", 3 } });
- var returnsFalse = new ExpressionValidator("((test is 1) and (test2 is 2))").Validates(new Dictionary() { { "test", 1 }, { "test2", 3 } });
+ var data = new Dictionary { { "test", 1 }, { "test2", 2 }, { "test3", 3 } };
+ var returnsTrue = new ExpressionBooleanValidator { Expression = "((test is 1) and (test2 is 2)) or (test3 is 3)", Data = data }.Validates();
+ var returnsFalse = new ExpressionBooleanValidator { Expression = "((test is 1) and (test2 is 3)) or (test3 is 4)", Data = data }.Validates();
Assert.IsTrue(returnsTrue);
Assert.IsFalse(returnsFalse);
}
-
+
[TestMethod]
public void TestComplexOrExpression()
{
- var returnsTrue = new ExpressionValidator("((test is 1) or (test2 is 2)) and (test3 is 3)").Validates(new Dictionary() { { "test", 1 }, { "test2", 3 }, { "test3", 3 } });
- var returnsFalse = new ExpressionValidator("((test is 1) or (test2 is 2))").Validates(new Dictionary() { { "test", 3 }, { "test2", 3 } });
+ var data = new Dictionary { { "test", 1 }, { "test2", 2 }, { "test3", 3 } };
+ var returnsTrue = new ExpressionBooleanValidator { Expression = "((test is 1) or (test2 is 2)) and (test3 is 3)", Data = data }.Validates();
+ var returnsFalse = new ExpressionBooleanValidator { Expression = "((test is 2) or (test2 is 1))", Data = data }.Validates();
Assert.IsTrue(returnsTrue);
Assert.IsFalse(returnsFalse);
}
-
+
[TestMethod]
public void TestComplexExpression()
{
- var returnsTrue = new ExpressionValidator("((test is 1) or (test2 is 2)) and (test3 is 3)").Validates(new Dictionary() { { "test", 1 }, { "test2", 3 }, { "test3", 3 } });
- var returnsFalse = new ExpressionValidator("((test is 1) or (test2 is 2))").Validates(new Dictionary() { { "test", 3 }, { "test2", 3 } });
+ var data = new Dictionary { { "test", 1 }, { "test2", 2 }, { "test3", 3 } };
+ var returnsTrue = new ExpressionBooleanValidator { Expression = "((test is 1) or (test2 is 2)) and (test3 is 3)", Data = data }.Validates();
+ var returnsFalse = new ExpressionBooleanValidator { Expression = "((test is 2) or (test2 is 1))", Data = data }.Validates();
Assert.IsTrue(returnsTrue);
Assert.IsFalse(returnsFalse);
@@ -118,8 +129,9 @@ public void TestComplexExpression()
[TestMethod]
public void TestMultipleStringComparisons()
{
- var returnsTrue = new ExpressionValidator("(test is 'test') and (test2 is 'test2')").Validates(new Dictionary() { { "test", "test" }, { "test2", "test2" } });
- var returnsFalse = new ExpressionValidator("(test is 'test') and (test2 is 'test2')").Validates(new Dictionary() { { "test", "test" }, { "test2", "test3" } });
+ var data = new Dictionary { { "test", "test" }, { "test2", "test2" } };
+ var returnsTrue = new ExpressionBooleanValidator { Expression = "(test is 'test') and (test2 is 'test2')", Data = data }.Validates();
+ var returnsFalse = new ExpressionBooleanValidator { Expression = "(test is 'test') and (test2 is 'test')", Data = data }.Validates();
Assert.IsTrue(returnsTrue);
Assert.IsFalse(returnsFalse);
diff --git a/HtmtTests/HelperTest.cs b/HtmtTests/HelperTest.cs
deleted file mode 100644
index ca61412..0000000
--- a/HtmtTests/HelperTest.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using Htmt;
-
-namespace HtmtTests;
-
-[TestClass]
-public class HelperTest
-{
- [TestMethod]
- public void TestReplaceKeysWithData()
- {
- var data = new Dictionary { { "name", "John Doe" } };
- var result = Helper.ReplaceKeysWithData("Hello, {name}!", data);
-
- Assert.AreEqual("Hello, John Doe!", result);
- }
-
- [TestMethod]
- public void TestReplaceKeysWithDataWithMultipleKeys()
- {
- var data = new Dictionary { { "name", "John Doe" }, { "age", 30 } };
- var result = Helper.ReplaceKeysWithData("Hello, {name}! You are {age} years old.", data);
-
- Assert.AreEqual("Hello, John Doe! You are 30 years old.", result);
- }
-
- [TestMethod]
- public void TestReplaceKeysWithDataWithEmptyData()
- {
- var result = Helper.ReplaceKeysWithData("Hello, {name}!", new Dictionary());
-
- Assert.AreEqual("Hello, !", result);
- }
-}
\ No newline at end of file
diff --git a/HtmtTests/ParserTest.cs b/HtmtTests/ParserTest.cs
index 26556d1..859b889 100644
--- a/HtmtTests/ParserTest.cs
+++ b/HtmtTests/ParserTest.cs
@@ -8,43 +8,55 @@ public class ParserTest
[TestMethod]
public void TestHtml5Document()
{
- const string template = "";
- var data = new Dictionary { { "title", "Hello, World!" }, { "heading", "Welcome to the world!" } };
+ const string template =
+ "";
+ var data = new Dictionary
+ { { "title", "Hello, World!" }, { "heading", "Welcome to the world!" } };
var parser = new Htmt.Parser { Template = template, Data = data };
var html = parser.ToHtml();
-
- Assert.AreEqual("Hello, World!Welcome to the world!
", html);
+
+ Assert.AreEqual(
+ "Hello, World!Welcome to the world!
",
+ html);
}
-
+
[TestMethod]
public void TestHtml5DocumentWithComments()
{
- const string template = "";
- var data = new Dictionary { { "title", "Hello, World!" }, { "heading", "Welcome to the world!" } };
+ const string template =
+ "";
+ var data = new Dictionary
+ { { "title", "Hello, World!" }, { "heading", "Welcome to the world!" } };
var parser = new Htmt.Parser { Template = template, Data = data };
var html = parser.ToHtml();
-
- Assert.AreEqual("Hello, World!Welcome to the world!
", html);
+
+ Assert.AreEqual(
+ "Hello, World!Welcome to the world!
",
+ html);
}
-
+
[TestMethod]
public void TestHtml4Document()
{
- const string template = "";
- var data = new Dictionary { { "title", "Hello, World!" }, { "heading", "Welcome to the world!" } };
+ const string template =
+ "";
+ var data = new Dictionary
+ { { "title", "Hello, World!" }, { "heading", "Welcome to the world!" } };
var parser = new Htmt.Parser { Template = template, Data = data };
var html = parser.ToHtml();
-
- Assert.AreEqual("Hello, World!Welcome to the world!
", html);
+
+ Assert.AreEqual(
+ "Hello, World!Welcome to the world!
",
+ html);
}
-
+
[TestMethod]
public void TestVoidElButClosed()
{
const string template = "";
var parser = new Htmt.Parser { Template = template };
var html = parser.ToHtml();
-
+
Assert.AreEqual("", html);
}
@@ -53,7 +65,7 @@ public void TestVoidElButOpen()
{
const string template = "
";
var parser = new Htmt.Parser { Template = template };
-
+
Assert.AreEqual("
", parser.ToHtml());
}
@@ -62,7 +74,7 @@ public void TestHtmlEntities()
{
const string template = "<div>Hello, World!</div>";
var parser = new Htmt.Parser { Template = template };
-
+
Assert.AreEqual("Hello, World!
", parser.ToHtml());
}
@@ -71,7 +83,7 @@ public void TestMoreHtmlEntities()
{
const string template = "→";
var parser = new Htmt.Parser { Template = template };
-
+
Assert.AreEqual("→", parser.ToHtml());
}
}
\ No newline at end of file
diff --git a/README.md b/README.md
index 08501b3..35a9a78 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,17 @@
# Htmt
-A simple templating language for .NET projects that is a superset of HTML/XML and is designed to be easy to read, write and have good editor support
-due to it being HTML/XML based and thus not needing any additional editor plugins. It fully supports
-trimming and native AOT compilation.
+A templating library for .NET projects designed to be easy to read, write and have good editor support
+without needing any additional editor plugins. It fully supports trimming and native AOT compilation.
## Features
- **Simple syntax**: Htmt is a superset of HTML/XML, so you can write your templates in any text editor.
- **Interpolation**: You can interpolate values from a data dictionary into your templates.
-- **Conditionals**: You can show or hide blocks using expressions.
+- **Modifiers**: You can modify the interpolated values using modifiers.
+- **Conditionals**: You can show or hide blocks using simple or complex expressions.
- **Partials**: You can include other templates inside your templates.
- **Loops**: You can loop over arrays and objects in your data dictionary.
-- **Custom attributes**: You can add custom attributes to your elements and write custom parsers for them.
+- **Extendable**: You can implement custom attribute parsers and expression modifiers.
## Example syntax
@@ -26,23 +26,17 @@ trimming and native AOT compilation.