Skip to content

Commit d3cddcb

Browse files
author
Kevin Petit
committed
Update Liquid renderer to Fluid latest version
1 parent a94b1f3 commit d3cddcb

File tree

9 files changed

+97
-148
lines changed

9 files changed

+97
-148
lines changed

src/Renderers/FluentEmail.Liquid/FluentEmail.Liquid.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
</PropertyGroup>
1313

1414
<ItemGroup>
15-
<PackageReference Include="Fluid.Core" Version="1.0.0" />
15+
<PackageReference Include="Fluid.Core" Version="2.0.13" />
1616
<PackageReference Include="Microsoft.Extensions.Options" Version="5.0.0" />
1717
</ItemGroup>
1818

src/Renderers/FluentEmail.Liquid/FluidViewTemplate.cs

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Text.Encodings.Web;
6+
using System.Threading.Tasks;
7+
using Fluid;
8+
using Fluid.Ast;
9+
10+
public class LiquidParser : FluidParser
11+
{
12+
public LiquidParser()
13+
{
14+
RegisterExpressionTag("layout", OnRegisterLayoutTag);
15+
RegisterEmptyTag("renderbody", OnRegisterRenderBodyTag);
16+
RegisterIdentifierBlock("section", OnRegisterSectionBlock);
17+
RegisterIdentifierTag("rendersection", OnRegisterSectionTag);
18+
}
19+
20+
private async ValueTask<Completion> OnRegisterLayoutTag(Expression expression, TextWriter writer, TextEncoder encoder, TemplateContext context)
21+
{
22+
const string viewExtension = ".liquid";
23+
24+
var relativeLayoutPath = (await expression.EvaluateAsync(context)).ToStringValue();
25+
26+
if (!relativeLayoutPath.EndsWith(viewExtension, StringComparison.OrdinalIgnoreCase))
27+
{
28+
relativeLayoutPath += viewExtension;
29+
}
30+
31+
context.AmbientValues["Layout"] = relativeLayoutPath;
32+
33+
return Completion.Normal;
34+
}
35+
36+
private async ValueTask<Completion> OnRegisterRenderBodyTag(TextWriter writer, TextEncoder encoder, TemplateContext context)
37+
{
38+
static void ThrowParseException()
39+
{
40+
throw new ParseException("Could not render body, Layouts can't be evaluated directly.");
41+
}
42+
43+
if (context.AmbientValues.TryGetValue("Body", out var body))
44+
{
45+
await writer.WriteAsync((string)body);
46+
}
47+
else
48+
{
49+
ThrowParseException();
50+
}
51+
52+
return Completion.Normal;
53+
}
54+
55+
private ValueTask<Completion> OnRegisterSectionBlock(string sectionName, IReadOnlyList<Statement> statements, TextWriter writer, TextEncoder encoder, TemplateContext context)
56+
{
57+
if (context.AmbientValues.TryGetValue("Sections", out var sections))
58+
{
59+
var dictionary = (Dictionary<string, List<Statement>>) sections;
60+
61+
dictionary[sectionName] = statements.ToList();
62+
}
63+
64+
return new ValueTask<Completion>(Completion.Normal);
65+
}
66+
67+
private async ValueTask<Completion> OnRegisterSectionTag(string sectionName, TextWriter writer, TextEncoder encoder, TemplateContext context)
68+
{
69+
if (context.AmbientValues.TryGetValue("Sections", out var sections))
70+
{
71+
var dictionary = (Dictionary<string, List<Statement>>) sections;
72+
73+
if (dictionary.TryGetValue(sectionName, out var section))
74+
{
75+
foreach(var statement in section)
76+
{
77+
await statement.WriteToAsync(writer, encoder, context);
78+
}
79+
}
80+
}
81+
82+
return Completion.Normal;
83+
}
84+
}

src/Renderers/FluentEmail.Liquid/LiquidRenderer.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ namespace FluentEmail.Liquid
1212
{
1313
public class LiquidRenderer : ITemplateRenderer
1414
{
15-
private static readonly Func<IFluidTemplate> FluidTemplateFactory = () => new FluidViewTemplate();
16-
1715
private readonly IOptions<LiquidRendererOptions> _options;
16+
private readonly LiquidParser _parser;
1817

1918
public LiquidRenderer(IOptions<LiquidRendererOptions> options)
2019
{
2120
_options = options;
21+
_parser = new LiquidParser();
2222
}
2323

2424
public string Parse<T>(string template, T model, bool isHtml = true)
@@ -42,9 +42,10 @@ public async Task<string> ParseAsync<T>(string template, T model, bool isHtml =
4242
["FileProvider"] = fileProvider,
4343
["Sections"] = new Dictionary<string, List<Statement>>()
4444
},
45-
ParserFactory = FluidViewTemplate.Factory,
46-
TemplateFactory = FluidTemplateFactory,
47-
FileProvider = fileProvider
45+
Options =
46+
{
47+
FileProvider = fileProvider
48+
}
4849
};
4950

5051
rendererOptions.ConfigureTemplateContext?.Invoke(context, model!);
@@ -63,7 +64,7 @@ public async Task<string> ParseAsync<T>(string template, T model, bool isHtml =
6364
return body;
6465
}
6566

66-
private static FluidViewTemplate ParseLiquidFile(
67+
private IFluidTemplate ParseLiquidFile(
6768
string path,
6869
IFileProvider? fileProvider)
6970
{
@@ -85,9 +86,9 @@ static void ThrowMissingFileProviderException()
8586
return ParseTemplate(sr.ReadToEnd());
8687
}
8788

88-
private static FluidViewTemplate ParseTemplate(string content)
89+
private IFluidTemplate ParseTemplate(string content)
8990
{
90-
if (!FluidViewTemplate.TryParse(content, out var template, out var errors))
91+
if (!_parser.TryParse(content, out var template, out var errors))
9192
{
9293
throw new Exception(string.Join(Environment.NewLine, errors));
9394
}

src/Renderers/FluentEmail.Liquid/Tags/LayoutTag.cs

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/Renderers/FluentEmail.Liquid/Tags/RegisterSectionBlock.cs

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/Renderers/FluentEmail.Liquid/Tags/RenderBodyTag.cs

Lines changed: 0 additions & 31 deletions
This file was deleted.

src/Renderers/FluentEmail.Liquid/Tags/RenderSectionTag.cs

Lines changed: 0 additions & 30 deletions
This file was deleted.

test/FluentEmail.Liquid.Tests/LiquidTests.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public class LiquidTests
2222
public void SetUp()
2323
{
2424
// default to have no file provider, only required when layout files are in use
25-
SetupRenderer(null);
25+
SetupRenderer();
2626
}
2727

2828
private static void SetupRenderer(
@@ -51,7 +51,6 @@ public void Model_With_List_Template_Matches()
5151
Assert.AreEqual("sup LUKE here is a list 123", email.Data.Body);
5252
}
5353

54-
5554
[Test]
5655
public void Custom_Context_Values()
5756
{
@@ -155,8 +154,7 @@ public void Should_be_able_to_use_project_layout()
155154
{
156155
SetupRenderer(new PhysicalFileProvider(Path.Combine(new FileInfo(Assembly.GetExecutingAssembly().Location).Directory!.FullName, "EmailTemplates")));
157156

158-
const string template = @"
159-
{% layout '_layout.liquid' %}
157+
const string template = @"{% layout '_layout.liquid' %}
160158
sup {{ Name }} here is a list {% for i in Numbers %}{{ i }}{% endfor %}";
161159

162160
var email = new Email(FromEmail)
@@ -167,14 +165,12 @@ public void Should_be_able_to_use_project_layout()
167165
Assert.AreEqual($"<h1>Hello!</h1>{Environment.NewLine}<div>{Environment.NewLine}sup LUKE here is a list 123</div>", email.Data.Body);
168166
}
169167

170-
171168
[Test]
172169
public void Should_be_able_to_use_embedded_layout()
173170
{
174171
SetupRenderer(new EmbeddedFileProvider(typeof(LiquidTests).Assembly, "FluentEmail.Liquid.Tests.EmailTemplates"));
175172

176-
const string template = @"
177-
{% layout '_embedded.liquid' %}
173+
const string template = @"{% layout '_embedded.liquid' %}
178174
sup {{ Name }} here is a list {% for i in Numbers %}{{ i }}{% endfor %}";
179175

180176
var email = new Email(FromEmail)

0 commit comments

Comments
 (0)