Skip to content
Merged
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
42 changes: 42 additions & 0 deletions source/Handlebars.Test/IssueTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,48 @@ public void UnrecognisedExpressionThrowsOutOfMemoryException()
Assert.Throws<HandlebarsCompilerException>(()=> Handlebars.Compile(source));
}

// Issue: https://github.com/Handlebars-Net/Handlebars.Net/issues/462
// Compile replaces \\ (double backslash) with \ (single backslash)
[Fact]
public void Issue462_DoubleBackslashPreservedInOutput()
{
var handlebars = Handlebars.Create();
// Template contains two backslashes as literal text
var compiledTemplate = handlebars.Compile(@"\\");
var result = compiledTemplate(null);
Assert.Equal(@"\\", result);
}

[Fact]
public void Issue462_SingleBackslashPreservedInOutput()
{
var handlebars = Handlebars.Create();
var compiledTemplate = handlebars.Compile(@"\");
var result = compiledTemplate(null);
Assert.Equal(@"\", result);
}

[Fact]
public void Issue462_DoubleBackslashBeforeExpressionStillCollapses()
{
// \\{{name}} should still produce a single literal backslash followed by the evaluated expression
var handlebars = Handlebars.Create();
var compiledTemplate = handlebars.Compile(@"\\{{name}}");
var result = compiledTemplate(new { name = "World" });
Assert.Equal(@"\World", result);
}

[Fact]
public void Issue462_DoubleBackslashInMixedTemplate()
{
// Template with backslashes mixed: \\to preserves both backslashes (not before {{),
// but \\{{name}} collapses to single backslash + evaluated expression (spec behavior)
var handlebars = Handlebars.Create();
var compiledTemplate = handlebars.Compile(@"path\\to\\{{name}}");
var result = compiledTemplate(new { name = "file" });
Assert.Equal(@"path\\to\file", result);
}

// Issue: https://github.com/Handlebars-Net/Handlebars.Net/issues/539
// Parent context (../) resolves to wrong value inside a custom block helper used within #each
[Fact]
Expand Down
14 changes: 12 additions & 2 deletions source/Handlebars/Compiler/Lexer/Tokenizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
private static readonly Parser PartialParser = new PartialParser();
private static readonly Parser BlockWordParser = new BlockWordParser();
private static readonly Parser BlockParamsParser = new BlockParamsParser();
//TODO: structure parser

Check warning on line 15 in source/Handlebars/Compiler/Lexer/Tokenizer.cs

View workflow job for this annotation

GitHub Actions / SonarCloud

Complete the task associated to this 'TODO' comment.

public static IEnumerable<Token> Tokenize(ExtendedStringReader source)
{
Expand Down Expand Up @@ -122,8 +122,18 @@
{
if ((char)node == '\\' && (char)source.Peek() == '\\')
{
source.Read();
buffer.Append('\\');
source.Read(); // consume second '\'
if ((char)source.Peek() == '{')
{
// \\{{ → single literal backslash followed by evaluated expression
buffer.Append('\\');
}
else
{
// \\ not followed by {{ → preserve both backslashes verbatim
buffer.Append('\\');
buffer.Append('\\');
}
node = source.Read();
}
else if ((char)node == '\\' && (char)source.Peek() == '{')
Expand Down
Loading