Unexpected HTML escaping with custom toString in Handlebars helpers
0 reputation · 22 Jan 2021, 10:40 UTC
0 reputation · 22 Jan 2021, 10:40 UTC
Handlebars core escapes double mustache output by default and renders triple mustache without escaping. Helpers can influence this by returning a SafeString or by using the escape option.
The design question is how escaping is applied when the template value is an object with a custom toString and the helper is intended to emit safe HTML. The documented behavior for double mustache is to escape the string result, and triple mustache bypasses escaping. It is unclear how these rules interact with SafeString return values and with objects whose stringification is defined by custom toString.
For a consistent rendering contract, clarification is needed on the precedence of SafeString marking versus explicit mustache delimiters, and on whether escaping is applied before or after toString conversion.
Does Handlebars apply escaping to the result of toString before checking SafeString status? Is a SafeString returned from a helper treated identically to triple mustache output when the helper is invoked with double mustache? Under what conditions does custom toString affect escaping safety?
35275 reputation · 22 Jan 2021, 18:07 UTC
Handlebars applies escaping to the final string result of a helper's execution. If a helper is invoked with double mustaches ({{helper}}), Handlebars will escape the output unless the returned value is explicitly marked as a SafeString. A SafeString acts as a signal to the renderer to bypass escaping, making its behavior identical to triple mustache ({{{helper}}}) output regardless of the delimiters used in the template.
When a helper returns an object with a custom toString method rather than a primitive string or a SafeString, the following sequence occurs:
valueOf then toString).Because the toString conversion happens before the escaping check, a custom toString method cannot inherently signal that its output is "safe." If you need the output of a custom object to avoid escaping while using double mustaches, the helper must wrap that object's string representation in a SafeString before returning it.
To verify this behavior in your specific environment (assuming Handlebars 4.x), you can use the following scoped test:
const Handlebars = require('handlebars');
// Object with custom toString
const customObj = {
toString: () => '<b>Bold</b>'
};
Handlebars.registerHelper('testHelper', () => customObj);
const template = Handlebars.compile('Double: {{testHelper}} | Triple: {{{testHelper}}}');
console.log(template({}));
// Expected: Double: <b>Bold</b> | Triple: <b>Bold</b>
To bypass escaping for the object, modify the helper to return new Handlebars.SafeString(customObj.toString()).
Missing Diagnostic: Please confirm if the helper is returning the custom object directly or if it is returning a string generated by that object, as this determines if the SafeString wrapper is being bypassed.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.