janl/mustache.js — pull request #375 by ELLIOTTCABLE (2014-05-21 03:15:46+00:00)
Title: Implement a SafeValue wrapper for helper functions.

Handlebars seems to provide a `SafeString` wrapper-type for helpers; with it, a helper can create string-y content that is known by the helper (i.e. implementation-code-side) to be ‘escape-safe.’

This means that the *template writer* needs no knowledge of whether the `{{generate}}` helper needs to be called with two brackets or three brackets. That's desirable, as maintaining that knowledge lessens separation of concerns. (Also, tell me you haven't forgotten at least a billion times, and used the wrong number of brackets due to forgetting which your helper expected? Best case, that forgetfulness will leave some content escaped and showing up to the client as HTML-source … and worst case, you've got an injection vulnerability 'cuz you used triple-brackets one time too often.)

----

For my implementation approach, I decided upon a duck-typing approach: a helper or library need only wrap values into some sort of structure with an `unwrap()` method, that returns a Mustache-friendly value; and then set a `safe` property to a truthy value on that structure. Everything else is ignored by my implementation.

For convenience, I've provided a `mustache.SafeValue` constructor, to do exactly that. All told, with this patch, all a helper needs to do to prevent their content being escaped, even in double-brackets, is:

view =
generate: ->
new mustache.SafeValue "#{generate_content()}"

----

I have one remaining concern with my approach: helpers, when telling mustache that their content is safe, become responsible for ensuring that it *is* safe. This means that a helper that's obtaining user-generated content from somewhere has to do its own escaping. That's not exactly world-shocking news or anything, but I'm suspicious that there's an elegant way to reduce the helper/library-writer needing to worry about that.

----

Feedback appreciated before a merge; this patch isn't quite ready yet.

(This is currently failing a *ton* of tests on my machine, despite the tiny footprint of the changes … but I'm fairly convinced that's an environmental issue, or due to me not understanding how to set up this project's test-suite. I've done some differentiation, and changes as simple as a noop `if`/`then` were causing tests to fail. I have no idea why.)