Skip to content

Commit 1a21569

Browse files
committed
Proper JValue handling in partials
Handlebars-Net/Handlebars.Net#428
1 parent 465e693 commit 1a21569

File tree

6 files changed

+121
-4
lines changed

6 files changed

+121
-4
lines changed

source/Handlebars.Extension.Test/IssueTests.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Linq;
12
using HandlebarsDotNet.Extension.NewtonsoftJson;
23
using Newtonsoft.Json.Linq;
34
using Xunit;
@@ -57,5 +58,36 @@ public class ClassOfTest
5758
Nested2 = (object)null
5859
});
5960
}
61+
62+
// issue: https://github.com/Handlebars-Net/Handlebars.Net/issues/428
63+
[Fact]
64+
public void PartialParametersInsideEachTest()
65+
{
66+
var handlebars = Handlebars.Create();
67+
handlebars.Configuration.UseNewtonsoftJson();
68+
69+
const string source = "{{#each itemType}}{{>partial item=this}}{{/each}}";
70+
const string partialContent = @"{{item}}";
71+
72+
handlebars.RegisterTemplate("partial", partialContent);
73+
74+
var template = handlebars.Compile(source);
75+
76+
var data = new
77+
{
78+
itemType = new JObject()
79+
{
80+
["1"] = "1",
81+
["3"] = "3",
82+
["5"] = "5",
83+
["7"] = "7"
84+
}
85+
};
86+
87+
var actual = template(data);
88+
var expected = data.itemType.Properties().Select(o => o.Value.Value<string>());
89+
90+
Assert.Equal(actual, string.Join("", expected));
91+
}
6092
}
6193
}

source/Handlebars.Extension/Handlebars.Extension.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
</ItemGroup>
5656

5757
<ItemGroup>
58-
<PackageReference Include="Handlebars.Net" Version="2.0.3" />
58+
<PackageReference Include="Handlebars.Net" Version="2.0.4" />
5959
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
6060
</ItemGroup>
6161

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using HandlebarsDotNet.ObjectDescriptors;
3+
using HandlebarsDotNet.PathStructure;
4+
using Newtonsoft.Json.Linq;
5+
6+
namespace HandlebarsDotNet.Extension.NewtonsoftJson
7+
{
8+
internal class JValueDescriptorProvider : IObjectDescriptorProvider
9+
{
10+
private static readonly Type Type = typeof(JValue);
11+
private static readonly JValueMemberAccessor MemberAccessor = new JValueMemberAccessor();
12+
13+
public bool TryGetDescriptor(Type type, out ObjectDescriptor value)
14+
{
15+
if (Type != type)
16+
{
17+
value = ObjectDescriptor.Empty;
18+
return false;
19+
}
20+
21+
value = new ObjectDescriptor(
22+
typeof(JObject),
23+
MemberAccessor,
24+
(d, o) =>
25+
{
26+
var jValue = (o as JValue)?.Value;
27+
if (jValue == null || !ObjectDescriptorFactory.Current.TryGetDescriptor(jValue.GetType(), out var localDescriptor))
28+
return new ChainSegment[0];
29+
30+
return new ObjectAccessor(jValue, localDescriptor).Properties;
31+
},
32+
self => new JValueIterator()
33+
);
34+
35+
return true;
36+
}
37+
}
38+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using HandlebarsDotNet.Compiler;
3+
using HandlebarsDotNet.Iterators;
4+
using HandlebarsDotNet.ObjectDescriptors;
5+
using HandlebarsDotNet.PathStructure;
6+
using Newtonsoft.Json.Linq;
7+
8+
namespace HandlebarsDotNet.Extension.NewtonsoftJson
9+
{
10+
internal class JValueIterator : IIterator
11+
{
12+
public void Iterate(
13+
in EncodedTextWriter writer,
14+
BindingContext context,
15+
ChainSegment[] blockParamsVariables,
16+
object input,
17+
TemplateDelegate template,
18+
TemplateDelegate ifEmpty)
19+
{
20+
var value = (input as JValue)?.Value;
21+
if(value == null || !ObjectDescriptorFactory.Current.TryGetDescriptor(value.GetType(), out var descriptor)) return;
22+
23+
descriptor.Iterator.Iterate(writer, context, blockParamsVariables, value, template, ifEmpty);
24+
}
25+
}
26+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using HandlebarsDotNet.MemberAccessors;
2+
using HandlebarsDotNet.ObjectDescriptors;
3+
using HandlebarsDotNet.PathStructure;
4+
using Newtonsoft.Json.Linq;
5+
6+
namespace HandlebarsDotNet.Extension.NewtonsoftJson
7+
{
8+
internal class JValueMemberAccessor : IMemberAccessor
9+
{
10+
public bool TryGetValue(object instance, ChainSegment memberName, out object? value)
11+
{
12+
var obj = (instance as JValue)?.Value;
13+
if (obj == null || !ObjectDescriptorFactory.Current.TryGetDescriptor(obj.GetType(), out var descriptor))
14+
{
15+
value = null;
16+
return false;
17+
}
18+
19+
return descriptor.MemberAccessor.TryGetValue(obj, memberName, out value);
20+
}
21+
}
22+
}

source/Handlebars.Extension/JsonFeatureExtensions.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,13 @@ public static HandlebarsConfiguration UseNewtonsoftJson(this HandlebarsConfigura
2727

2828
internal class JsonFeature : IFeature, IFeatureFactory
2929
{
30-
private static readonly JObjectDescriptorProvider JObjectDescriptorProvider = new JObjectDescriptorProvider();
31-
3230
public void OnCompiling(ICompiledHandlebarsConfiguration configuration)
3331
{
3432
var providers = configuration.ObjectDescriptorProviders;
3533
var objectDescriptorProvider = providers.OfType<ObjectDescriptorProvider>().Single();
3634
providers.Add(new JArrayDescriptorProvider(objectDescriptorProvider));
37-
providers.Add(JObjectDescriptorProvider);
35+
providers.Add(new JObjectDescriptorProvider());
36+
providers.Add(new JValueDescriptorProvider());
3837

3938
configuration.FormatterProviders.Add(new JFormatterProvider());
4039
}

0 commit comments

Comments
 (0)