diff --git a/source/Handlebars.Test/IteratorTests.cs b/source/Handlebars.Test/IteratorTests.cs index 13056a83..84339f7b 100644 --- a/source/Handlebars.Test/IteratorTests.cs +++ b/source/Handlebars.Test/IteratorTests.cs @@ -247,6 +247,26 @@ public void WithLast() Assert.Equal("Hello,\n0. Erik (Erik is not last)\n1. Helen (Helen is last)", result); } + [Fact] + public void WithKey() + { + var source = "Hello,{{#each people}}\n{{@key}}. {{name}}{{/each}}"; + var template = Handlebars.Compile(source); + var data = new + { + people = new[]{ + new { + name = "Erik" + }, + new { + name = "Helen" + } + } + }; + var result = template(data); + Assert.Equal("Hello,\n0. Erik\n1. Helen", result); + } + [Fact] public void Empty() { diff --git a/source/Handlebars/Configuration/Compatibility.cs b/source/Handlebars/Configuration/Compatibility.cs index 7ef8c8fb..73f6f5f4 100644 --- a/source/Handlebars/Configuration/Compatibility.cs +++ b/source/Handlebars/Configuration/Compatibility.cs @@ -1,4 +1,6 @@ -namespace HandlebarsDotNet +using System; + +namespace HandlebarsDotNet { /// /// Contains feature flags that breaks compatibility with Handlebarsjs. @@ -8,6 +10,7 @@ public class Compatibility /// /// If enables support for @last in object properties iterations. /// + [Obsolete("@last is supported on Handlebarsjs, so it is always enabled, and the setting should be removed.")] public bool SupportLastInObjectIterations { get; set; } = true; /// diff --git a/source/Handlebars/Iterators/ArrayIterator.cs b/source/Handlebars/Iterators/ArrayIterator.cs index 7aa51dcb..15f5355e 100644 --- a/source/Handlebars/Iterators/ArrayIterator.cs +++ b/source/Handlebars/Iterators/ArrayIterator.cs @@ -39,7 +39,7 @@ TemplateDelegate ifEmpty if (index == 1) iterator.First = BoxedValues.False; if (index == lastIndex) iterator.Last = BoxedValues.True; - iterator.Index = objectIndex; + iterator.Key = iterator.Index = objectIndex; blockParamsValues[_0] = value; blockParamsValues[_1] = objectIndex; diff --git a/source/Handlebars/Iterators/CollectionIterator'2.cs b/source/Handlebars/Iterators/CollectionIterator'2.cs index 34bb99f0..4e39d0eb 100644 --- a/source/Handlebars/Iterators/CollectionIterator'2.cs +++ b/source/Handlebars/Iterators/CollectionIterator'2.cs @@ -42,7 +42,7 @@ TemplateDelegate ifEmpty if (index == 1) iterator.First = BoxedValues.False; if (index == lastIndex) iterator.Last = BoxedValues.True; - iterator.Index = objectIndex; + iterator.Key = iterator.Index = objectIndex; blockParamsValues[_0] = value; blockParamsValues[_1] = objectIndex; diff --git a/source/Handlebars/Iterators/CollectionIterator.cs b/source/Handlebars/Iterators/CollectionIterator.cs index b6c4471b..f34ad1ff 100644 --- a/source/Handlebars/Iterators/CollectionIterator.cs +++ b/source/Handlebars/Iterators/CollectionIterator.cs @@ -43,7 +43,7 @@ TemplateDelegate ifEmpty if (index == 1) iterator.First = BoxedValues.False; if (index == lastIndex) iterator.Last = BoxedValues.True; - iterator.Index = objectIndex; + iterator.Key = iterator.Index = objectIndex; blockParamsValues[_0] = value; blockParamsValues[_1] = objectIndex; diff --git a/source/Handlebars/Iterators/DictionaryIterator'2.cs b/source/Handlebars/Iterators/DictionaryIterator'2.cs index adb83f9c..01a4fffd 100644 --- a/source/Handlebars/Iterators/DictionaryIterator'2.cs +++ b/source/Handlebars/Iterators/DictionaryIterator'2.cs @@ -19,7 +19,7 @@ TemplateDelegate ifEmpty ) { using var innerContext = context.CreateFrame(); - var iterator = new ObjectIteratorValues(innerContext); + var iterator = new IteratorValues(innerContext); var blockParamsValues = new BlockParamsValues(innerContext, blockParamsVariables); blockParamsValues.CreateProperty(0, out var _0); diff --git a/source/Handlebars/Iterators/DictionaryIterator.cs b/source/Handlebars/Iterators/DictionaryIterator.cs index 82b58f5b..e2bf1144 100644 --- a/source/Handlebars/Iterators/DictionaryIterator.cs +++ b/source/Handlebars/Iterators/DictionaryIterator.cs @@ -19,7 +19,7 @@ TemplateDelegate ifEmpty ) { using var innerContext = context.CreateFrame(); - var iterator = new ObjectIteratorValues(innerContext); + var iterator = new IteratorValues(innerContext); var blockParamsValues = new BlockParamsValues(innerContext, blockParamsVariables); blockParamsValues.CreateProperty(0, out var _0); diff --git a/source/Handlebars/Iterators/DynamicObjectIterator.cs b/source/Handlebars/Iterators/DynamicObjectIterator.cs index b972a2be..c83d92f6 100644 --- a/source/Handlebars/Iterators/DynamicObjectIterator.cs +++ b/source/Handlebars/Iterators/DynamicObjectIterator.cs @@ -28,7 +28,7 @@ TemplateDelegate ifEmpty ) { using var innerContext = context.CreateFrame(); - var iterator = new ObjectIteratorValues(innerContext); + var iterator = new IteratorValues(innerContext); var blockParamsValues = new BlockParamsValues(innerContext, blockParamsVariables); blockParamsValues.CreateProperty(0, out var _0); diff --git a/source/Handlebars/Iterators/EnumerableIterator'2.cs b/source/Handlebars/Iterators/EnumerableIterator'2.cs index c9564a56..699414c8 100644 --- a/source/Handlebars/Iterators/EnumerableIterator'2.cs +++ b/source/Handlebars/Iterators/EnumerableIterator'2.cs @@ -43,8 +43,8 @@ TemplateDelegate ifEmpty if (index == 1) iterator.First = BoxedValues.False; if (current.IsLast) iterator.Last = BoxedValues.True; - - iterator.Index = indexObject; + + iterator.Key = iterator.Index = indexObject; blockParamsValues[_0] = value; blockParamsValues[_1] = indexObject; diff --git a/source/Handlebars/Iterators/EnumerableIterator.cs b/source/Handlebars/Iterators/EnumerableIterator.cs index e3a800af..7e8d78b2 100644 --- a/source/Handlebars/Iterators/EnumerableIterator.cs +++ b/source/Handlebars/Iterators/EnumerableIterator.cs @@ -42,8 +42,8 @@ TemplateDelegate ifEmpty if (index == 1) iterator.First = BoxedValues.False; if (current.IsLast) iterator.Last = BoxedValues.True; - - iterator.Index = indexObject; + + iterator.Key = iterator.Index = indexObject; blockParamsValues[_0] = value; blockParamsValues[_1] = indexObject; diff --git a/source/Handlebars/Iterators/ListIterator'2.cs b/source/Handlebars/Iterators/ListIterator'2.cs index 3bfcb40a..d6cfca59 100644 --- a/source/Handlebars/Iterators/ListIterator'2.cs +++ b/source/Handlebars/Iterators/ListIterator'2.cs @@ -40,8 +40,8 @@ TemplateDelegate ifEmpty if (index == 1) iterator.First = BoxedValues.False; if (index == lastIndex) iterator.Last = BoxedValues.True; - - iterator.Index = objectIndex; + + iterator.Key = iterator.Index = objectIndex; blockParamsValues[_0] = value; blockParamsValues[_1] = objectIndex; diff --git a/source/Handlebars/Iterators/ListIterator.cs b/source/Handlebars/Iterators/ListIterator.cs index 5a78bd2e..977ac4eb 100644 --- a/source/Handlebars/Iterators/ListIterator.cs +++ b/source/Handlebars/Iterators/ListIterator.cs @@ -40,8 +40,8 @@ TemplateDelegate ifEmpty if (index == 1) iterator.First = BoxedValues.False; if (index == lastIndex) iterator.Last = BoxedValues.True; - - iterator.Index = objectIndex; + + iterator.Key = iterator.Index = objectIndex; blockParamsValues[_0] = value; blockParamsValues[_1] = objectIndex; diff --git a/source/Handlebars/Iterators/ObjectIterator.cs b/source/Handlebars/Iterators/ObjectIterator.cs index 0e01eed7..6b9c099a 100644 --- a/source/Handlebars/Iterators/ObjectIterator.cs +++ b/source/Handlebars/Iterators/ObjectIterator.cs @@ -25,7 +25,7 @@ TemplateDelegate ifEmpty ) { using var innerContext = context.CreateFrame(); - var iterator = new ObjectIteratorValues(innerContext); + var iterator = new IteratorValues(innerContext); var blockParamsValues = new BlockParamsValues(innerContext, blockParamsVariables); blockParamsValues.CreateProperty(0, out var _0); diff --git a/source/Handlebars/Iterators/ReadOnlyCollectionIterator'2.cs b/source/Handlebars/Iterators/ReadOnlyCollectionIterator'2.cs index 52373327..2a793078 100644 --- a/source/Handlebars/Iterators/ReadOnlyCollectionIterator'2.cs +++ b/source/Handlebars/Iterators/ReadOnlyCollectionIterator'2.cs @@ -42,7 +42,7 @@ TemplateDelegate ifEmpty if (index == 1) iterator.First = BoxedValues.False; if (index == lastIndex) iterator.Last = BoxedValues.True; - iterator.Index = objectIndex; + iterator.Key = iterator.Index = objectIndex; blockParamsValues[_0] = value; blockParamsValues[_1] = objectIndex; diff --git a/source/Handlebars/Iterators/ReadOnlyDictionaryIterator'2.cs b/source/Handlebars/Iterators/ReadOnlyDictionaryIterator'2.cs index 93688dd5..2847a126 100644 --- a/source/Handlebars/Iterators/ReadOnlyDictionaryIterator'2.cs +++ b/source/Handlebars/Iterators/ReadOnlyDictionaryIterator'2.cs @@ -19,7 +19,7 @@ TemplateDelegate ifEmpty ) { using var innerContext = context.CreateFrame(); - var iterator = new ObjectIteratorValues(innerContext); + var iterator = new IteratorValues(innerContext); var blockParamsValues = new BlockParamsValues(innerContext, blockParamsVariables); blockParamsValues.CreateProperty(0, out var _0); diff --git a/source/Handlebars/Iterators/ReadOnlyListIterator'2.cs b/source/Handlebars/Iterators/ReadOnlyListIterator'2.cs index 917328ef..85057623 100644 --- a/source/Handlebars/Iterators/ReadOnlyListIterator'2.cs +++ b/source/Handlebars/Iterators/ReadOnlyListIterator'2.cs @@ -40,8 +40,8 @@ TemplateDelegate ifEmpty if (index == 1) iterator.First = BoxedValues.False; if (index == lastIndex) iterator.Last = BoxedValues.True; - - iterator.Index = objectIndex; + + iterator.Key = iterator.Index = objectIndex; blockParamsValues[_0] = value; blockParamsValues[_1] = objectIndex; diff --git a/source/Handlebars/ValueProviders/IteratorValues.cs b/source/Handlebars/ValueProviders/IteratorValues.cs index 27d6e565..a12f774c 100644 --- a/source/Handlebars/ValueProviders/IteratorValues.cs +++ b/source/Handlebars/ValueProviders/IteratorValues.cs @@ -8,7 +8,7 @@ namespace HandlebarsDotNet.ValueProviders public readonly ref struct IteratorValues { private readonly FixedSizeDictionary _data; - + private readonly EntryIndex[] _wellKnownVariables; [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -21,8 +21,9 @@ public IteratorValues(BindingContext bindingContext) : this() _data.AddOrReplace(ChainSegment.First, BoxedValues.True, out _wellKnownVariables[(int) ChainSegment.First.WellKnownVariable]); _data.AddOrReplace(ChainSegment.Last, BoxedValues.False, out _wellKnownVariables[(int) ChainSegment.Last.WellKnownVariable]); _data.AddOrReplace(ChainSegment.Index, BoxedValues.Zero, out _wellKnownVariables[(int) ChainSegment.Index.WellKnownVariable]); + _data.AddOrReplace(ChainSegment.Key, null, out _wellKnownVariables[(int)ChainSegment.Key.WellKnownVariable]); } - + public object Value { get => _data[_wellKnownVariables[(int) ChainSegment.Value.WellKnownVariable]]; @@ -41,6 +42,12 @@ public object Index set => _data[_wellKnownVariables[(int) ChainSegment.Index.WellKnownVariable]] = value; } + public object Key + { + get => _data[_wellKnownVariables[(int)ChainSegment.Key.WellKnownVariable]]; + set => _data[_wellKnownVariables[(int)ChainSegment.Key.WellKnownVariable]] = value; + } + public object Last { get => _data[_wellKnownVariables[(int) ChainSegment.Last.WellKnownVariable]]; diff --git a/source/Handlebars/ValueProviders/ObjectIteratorValues.cs b/source/Handlebars/ValueProviders/ObjectIteratorValues.cs index cfe0f921..cc6aade4 100644 --- a/source/Handlebars/ValueProviders/ObjectIteratorValues.cs +++ b/source/Handlebars/ValueProviders/ObjectIteratorValues.cs @@ -1,32 +1,22 @@ using HandlebarsDotNet.Collections; using HandlebarsDotNet.PathStructure; using HandlebarsDotNet.Runtime; +using System; namespace HandlebarsDotNet.ValueProviders { + [Obsolete("Use IteratorValues")] public readonly ref struct ObjectIteratorValues { private readonly FixedSizeDictionary _data; - private readonly bool _supportLastInObjectIterations; - + private readonly EntryIndex[] _wellKnownVariables; public ObjectIteratorValues(BindingContext bindingContext) : this() { - var configuration = bindingContext.Configuration; - _data = bindingContext.ContextDataObject; - _supportLastInObjectIterations = configuration.Compatibility.SupportLastInObjectIterations; _wellKnownVariables = bindingContext.WellKnownVariables; - if (!_supportLastInObjectIterations) - { - var undefined = UndefinedBindingResult.Create(ChainSegment.Last); - _data.AddOrReplace(ChainSegment.Last, undefined, out _wellKnownVariables[(int) ChainSegment.Last.WellKnownVariable]); - } - else - { - _data.AddOrReplace(ChainSegment.Last, BoxedValues.False, out _wellKnownVariables[(int) ChainSegment.Last.WellKnownVariable]); - } + _data.AddOrReplace(ChainSegment.Last, BoxedValues.False, out _wellKnownVariables[(int) ChainSegment.Last.WellKnownVariable]); _data.AddOrReplace(ChainSegment.Key, null, out _wellKnownVariables[(int) ChainSegment.Key.WellKnownVariable]); _data.AddOrReplace(ChainSegment.Value, null, out _wellKnownVariables[(int) ChainSegment.Value.WellKnownVariable]); @@ -61,11 +51,7 @@ public object Index public object Last { get => _data[_wellKnownVariables[(int) ChainSegment.Last.WellKnownVariable]]; - set - { - if(!_supportLastInObjectIterations) return; - _data[_wellKnownVariables[(int) ChainSegment.Last.WellKnownVariable]] = value; - } + set => _data[_wellKnownVariables[(int) ChainSegment.Last.WellKnownVariable]] = value; } } } \ No newline at end of file