Skip to content

Commit

Permalink
Add Templated Razor delegates
Browse files Browse the repository at this point in the history
  • Loading branch information
ltrzesniewski committed Dec 4, 2024
1 parent f8d7419 commit 8661d4b
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 1 deletion.
2 changes: 2 additions & 0 deletions src/RazorBlade.Analyzers/RazorBladeSourceGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ private static RazorCSharpDocument GenerateRazorCode(SourceText sourceText, Inpu
});

cfg.Features.Add(new ErrorOnTagHelperSyntaxTreePass());

cfg.AddTargetExtension(new TemplateTargetExtension { TemplateTypeName = "HelperResult" });
}
);

Expand Down
9 changes: 8 additions & 1 deletion src/RazorBlade.IntegrationTest/TestTemplate.cshtml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@using RazorBlade.IntegrationTest
@using System
@inherits RazorBlade.HtmlTemplate

<b>Hello, @Name!</b>
Expand All @@ -12,6 +12,13 @@
@br
@Html.Raw("<br>")

@{
Func<string, IEncodedContent> bold = @<b>@item</b>;
}

@bold("Bold text")
@bold("Other bold text")

@(new Footer())

@functions {
Expand Down
28 changes: 28 additions & 0 deletions src/RazorBlade.Library.Tests/RazorTemplateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,30 @@ public async Task should_buffer_output_until_flushed()
output.ToString().ShouldEqual("foo bar baz");
}

[Test]
public void should_execute_templated_delegate()
{
var template = new Template(t =>
{
Func<object, object> bold = item => new RazorTemplate.HelperResult(writer =>
{
t.PushWriter(writer);
t.WriteLiteral("<b>");
t.Write(item);
t.WriteLiteral("</b>");
t.PopWriter();
return Task.CompletedTask;
}
);

t.Write(bold("Bold text"));
t.WriteLiteral(" - ");
t.Write(bold("Other bold text"));
});

template.Render().ShouldEqual("<b>Bold text</b> - <b>Other bold text</b>");
}

private class Template(Func<Template, Task> executeAction) : RazorTemplate
{
public Template(Action<Template> executeAction)
Expand All @@ -252,6 +276,10 @@ protected internal override async Task ExecuteAsync()

protected internal override void Write(object? value)
{
if (value is IEncodedContent encodedContent)
encodedContent.WriteTo(Output);
else
WriteLiteral(value?.ToString());
}

protected internal override void BeginWriteAttribute(string name, string prefix, int prefixOffset, string suffix, int suffixOffset, int attributeValuesCount)
Expand Down
20 changes: 20 additions & 0 deletions src/RazorBlade.Library/RazorTemplate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -521,4 +521,24 @@ public void WriteTo(TextWriter textWriter)
public override string ToString()
=> Output.ToString();
}

/// <summary>
/// Represents a deferred write operation.
/// </summary>
[PublicAPI]
protected internal class HelperResult : IEncodedContent
{
private readonly Func<TextWriter, Task> _action;

/// <summary>
/// Creates a deferred operation.
/// </summary>
/// <param name="action">The action to execute.</param>
public HelperResult(Func<TextWriter, Task> action)
=> _action = action;

/// <inheritdoc />
public void WriteTo(TextWriter textWriter)
=> _action.Invoke(textWriter).GetAwaiter().GetResult();
}
}

0 comments on commit 8661d4b

Please sign in to comment.