handlebars.js icon indicating copy to clipboard operation
handlebars.js copied to clipboard

noEscape cause additions of integer values

Open christophermhawaudio opened this issue 2 years ago • 5 comments

Hello,

When I set the parameter "noEscape" to true, it seems that tokens are added instead of concatenated. So if I reference integers inside tokens, an addition will be realised if no separation character is present between tokens.

According to the documentation, "noEscape" is just a way to disable HTML characters escaping, and I think that a solution would be to use a string version of the variables referenced by the tokens instead of the variables values directly.

Here is an example of the bug with multiple cases: https://jsfiddle.net/mhd0k4ne/70/

Thanks.

christophermhawaudio avatar Mar 19 '22 11:03 christophermhawaudio

Any news about this bug?

christophermhawaudio avatar Apr 23 '22 10:04 christophermhawaudio

@jaylinski Excuse me, is there any progress on this?

rickyes avatar Jun 21 '22 05:06 rickyes

I opened a fix PR: https://github.com/handlebars-lang/handlebars.js/pull/1977

jaylinski avatar Aug 03 '23 23:08 jaylinski

Follownig up the discussion at #1977:

{{{a}}}{{{b}}}{{{c}}}

compiles to

{"compiler":[8,">= 4.3.0"],"main":function(container,depth0,helpers,partials,data) {
    var stack1, helper, alias1=container.propertyIsEnumerable, alias2=depth0 != null ? depth0 : (container.nullContext || {}), alias3=container.hooks.helperMissing, alias4="function";

  return ((stack1 = ((helper = (helper = helpers.a || (depth0 != null ? depth0.a : depth0)) != null ? helper : alias3),(typeof helper === alias4 ? helper.call(alias2,{"name":"a","hash":{},"data":data}) : helper))) != null ? stack1 : "")
    + ((stack1 = ((helper = (helper = helpers.b || (depth0 != null ? depth0.b : depth0)) != null ? helper : alias3),(typeof helper === alias4 ? helper.call(alias2,{"name":"b","hash":{},"data":data}) : helper))) != null ? stack1 : "")
    + ((stack1 = ((helper = (helper = helpers.c || (depth0 != null ? depth0.c : depth0)) != null ? helper : alias3),(typeof helper === alias4 ? helper.call(alias2,{"name":"c","hash":{},"data":data}) : helper))) != null ? stack1 : "");
},"useData":true}

which boils down to

input.a + input.b + input.c

which adds integer values, giving the wrong output.

But the template

a{{{a}}}{{{b}}}{{{c}}}

becomes something like

"a" + input.a + input.b + input.c

which will always be a string and concatenate numbers.

I think in order to achieve this always, we just need to make sure that

{{{a}}}{{{b}}}{{{c}}}

becomes

"" + input.a + input.b + input.c

In those cases where the buffer added to (buffer += ...), we don't need it, because the buffer should already be a string. I have to see wether I find the places to change this.

nknapp avatar Aug 06 '23 14:08 nknapp

The place to change this would be line 311.

Changing this to

bufferStart.prepend('return "" + ');

should also make sure that everything is handled like a string.

  • The downside is three more bytes for the template and each block and partial statement, even if not needed.
  • The downside of your change is three bytes per non-escaped mustache-expression.

Difficult to say which one will produce more bytes in average.

nknapp avatar Aug 06 '23 15:08 nknapp