xslate / p5-Text-Xslate

Scalable template engine for Perl5
https://metacpan.org/release/Text-Xslate
Other
121 stars 47 forks source link

Unexpected HTML escaping in macro concatenation #175

Closed mikeraynham closed 7 years ago

mikeraynham commented 7 years ago

See pull request #174 for a failing test.

When macro A concatenates strings with the output of macro B, and both macros mark their output as raw, the strings from macro A are unexpectedly HTML escaped. This only happens with the concatenation operator when used inside a macro. HTML escaping is not applied if the join method is used instead of the concatenation operator, or if the concatenation operator is used outside of a macro.

This:

 : macro br  { raw('<br>') }
 : macro div { raw('<div>' ~ br()  ~ '</div>') }
 : div()

Produces:

&lt;div&gt;<br>&lt;/div&gt;

Whereas this:

: macro br  { raw('<br>') }
: macro div { raw(['<div>', br(), '</div>'].join('')) }
: div()

Or this:

: macro br        { raw('<br>') }
: macro div_open  { raw('<div>') }
: macro div_close { raw('</div>') }
: div_open() ~ br() ~ div_close()

Produces:

<div><br></div>
syohex commented 7 years ago

This is expected behaviour.

 : macro div { raw('<div>' ~ br()  ~ '</div>') }

You should write as below.

 : macro div { raw(raw('<div>') ~ br()  ~ raw('</div>')) }

~ operator is applied before applying outside raw operator. And <div> is not marked as string while br() is marked as raw string so that ~ operator escapes unraw string(<div>). (And its result is marked as raw string while 2nd </div> is not marked as raw string, so right hand side is escaped).

join builtin arrayref function is just a Perl's buildin join function. It does not escape against array content.

mikeraynham commented 7 years ago

Thank you for the explanation.