Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public override void EndBlock(Processor processor, BlockToken token, BlockCloseT
{
if (sectionTag.SectionName.Equals(sectionEndTag.SectionName))
{
sectionTag.Tags = processor.CurrentTags;
sectionTag.Tags = sectionEndTag.CurrentTags ?? processor.CurrentTags;
sectionTag.EndPosition = sectionEndTag.EndPosition;
sectionTag.IsClosed = true;
}
Expand Down Expand Up @@ -128,6 +128,7 @@ public override bool TryClose(Processor processor, ref StringSlice slice, BlockT
SectionName = sectionName,
EndPosition = tagEnd,
ContentEndPosition = blockStart,
CurrentTags = processor.CurrentTags,
IsClosed = true
};

Expand Down
3 changes: 2 additions & 1 deletion src/Stubble.Core/Parser/TokenParsers/SectionTagParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public override void EndBlock(Processor processor, BlockToken token, BlockCloseT
{
if (sectionTag.SectionName.Equals(sectionEndTag.SectionName))
{
sectionTag.Tags = processor.CurrentTags;
sectionTag.Tags = sectionEndTag.CurrentTags ?? processor.CurrentTags;
sectionTag.EndPosition = sectionEndTag.EndPosition;
sectionTag.ContentEndPosition = sectionEndTag.ContentEndPosition;
sectionTag.IsClosed = true;
Expand Down Expand Up @@ -137,6 +137,7 @@ public override bool TryClose(Processor processor, ref StringSlice slice, BlockT
SectionName = sectionName,
EndPosition = tagEnd,
ContentEndPosition = blockStart,
CurrentTags = processor.CurrentTags,
IsClosed = true
};

Expand Down
7 changes: 7 additions & 0 deletions src/Stubble.Core/Tokens/SectionEndToken.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
// </copyright>

using Stubble.Core.Classes;

namespace Stubble.Core.Tokens
{
/// <summary>
Expand All @@ -24,5 +26,10 @@ public class SectionEndToken : BlockCloseToken
/// Gets or sets the end position for the content
/// </summary>
public int ContentEndPosition { get; set; }

/// <summary>
/// Gets or sets the tags that were active when this section was closed
/// </summary>
public Classes.Tags CurrentTags { get; set; }
}
}
21 changes: 21 additions & 0 deletions test/Stubble.Core.Tests/StubbleTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,27 @@ public void It_Should_Allow_A_Render_Function_WithContext_In_Lambda()
Assert.Equal("A is Cool", result);
}

[Fact]
public void It_Should_Use_Correct_Delimiters_In_Lambda_When_Delimiters_Change_After_Section()
{
// When delimiters change AFTER a lambda section closes, SectionToken.Tags
// is incorrectly set to the final processor.CurrentTags (the post-change
// delimiters) rather than the tags that were active when the section closed.
// This causes the render callback to parse the section body with wrong delimiters.
var stubble = new StubbleBuilder().Build();

var obj = new
{
value = "World",
test = new Func<string, Func<string, string>, object>((template, render) => render(template))
};

// Delimiters change to <% %>, lambda section uses <% %>, then delimiters revert to {{ }}.
// The lambda body "<% value %>" should be parsed with <% %> delimiters.
var result = stubble.Render("{{=<% %>=}}<%#test%><% value %><%/test%><%={{ }}=%>{{value}}", obj);
Assert.Equal("WorldWorld", result);
}

[Fact]
public void It_Should_Throw_When_Ambiguous_Match()
{
Expand Down
Loading