StubbleOrg / Stubble

Trimmed down {{mustache}} templates in .NET
Other
399 stars 58 forks source link

ValueGetter order is not deterministic and isn't always the expected order #99

Closed jlocke427 closed 4 years ago

jlocke427 commented 4 years ago

We have been playing around with Mustache templating for some projects and we noticed an odd issue with conditionals. I have attached a repository for you to take a look at with the minimum amount of code to reproduce the issue https://github.com/jlocke427/MustacheBug. It appears that how the dependent assemblies (Specifically Newtonsoft.json) are being loaded is changing the behavior of the template processing. If you run the Console application as is it will not produce the expected output.

`string template = "Condition is set to {{IsWorking}}.{{#IsWorking}} Condition is True{{/IsWorking}}";

string inputData = "{ IsWorking: true }";`

The expected value should be "Condition is set to True. Condition is True", but we are getting "Condition is set to True.".

However if we add in a JsonConvert.DeserializeObject<dynamic>("{}"); before we run the renderer it seems to work fine.

Any ideas as to why we are seeing this behavior?

Romanx commented 4 years ago

Hey @jlocke427,

Thanks for opening the issue. I took at a look at this and worked out that it's occuring due to us expecting the way we get values from an object to occur in a specific order. We store these in an ImmutableDictionary which we order the items before we store them. ImmutableDicitionary however isn't deterministic so sometimes will get a different order.

In this case the IDynamicMetaObjectProvider comes before the JObject value getter which the Stubble.JsonNet package provides and so it falls back to the default logic. In this case it finds the value correctly and caches it for the next lookup.

Sections are a little unique in mustache since it can be and if block or a loop depending on if the value is considered to be a collection of things. We work this out in a few way with IEnumerable being one of them. The value we cached is a JToken which implements IEnumerable which has no children so the section is considered falsey and the section is then not rendered.

I hope this makes some sense, i've got a fix for this which I should release today and i'll make a note below, thanks for the great reproduction case for this!

Romanx commented 4 years ago

Thanks @jlocke427 again for reporting. This has just been released in v1.9.3.

Please let us know if you still have any issues