Skip to content

Commit

Permalink
Merge pull request #994 from mozilla/fix-call-scope
Browse files Browse the repository at this point in the history
Allow {% call %} blocks to access parent scope. Fixes #906
  • Loading branch information
fdintino authored May 24, 2017
2 parents 5c2bf56 + 3fb9e9f commit efd2ee9
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 5 deletions.
15 changes: 10 additions & 5 deletions src/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -795,10 +795,11 @@ var Compiler = Object.extend({
this._compileAsyncLoop(node, frame, true);
},

_compileMacro: function(node) {
_compileMacro: function(node, frame) {
var args = [];
var kwargs = null;
var funcId = 'macro_' + this.tmpid();
var keepFrame = (frame !== undefined);

// Type check the definition of the args
lib.each(node.args.children, function(arg, i) {
Expand All @@ -824,14 +825,18 @@ var Compiler = Object.extend({
// arguments so support setting positional args with keywords
// args and passing keyword args as positional args
// (essentially default values). See runtime.js.
var frame = new Frame();
if (keepFrame) {
frame = frame.push(true);
} else {
frame = new Frame();
}
this.emitLines(
'var ' + funcId + ' = runtime.makeMacro(',
'[' + argNames.join(', ') + '], ',
'[' + kwargNames.join(', ') + '], ',
'function (' + realNames.join(', ') + ') {',
'var callerFrame = frame;',
'frame = new runtime.Frame();',
'frame = ' + ((keepFrame) ? 'frame.push(true);' : 'new runtime.Frame();'),
'kwargs = kwargs || {};',
'if (kwargs.hasOwnProperty("caller")) {',
'frame.set("caller", kwargs.caller); }'
Expand Down Expand Up @@ -865,7 +870,7 @@ var Compiler = Object.extend({
this.compile(node.body, frame);
});

this.emitLine('frame = callerFrame;');
this.emitLine('frame = ' + ((keepFrame) ? 'frame.pop();' : 'callerFrame;'));
this.emitLine('return new runtime.SafeString(' + bufferId + ');');
this.emitLine('});');
this.popBufferId();
Expand All @@ -874,7 +879,7 @@ var Compiler = Object.extend({
},

compileMacro: function(node, frame) {
var funcId = this._compileMacro(node, frame);
var funcId = this._compileMacro(node);

// Expose the macro to the templates
var name = node.name.value;
Expand Down
38 changes: 38 additions & 0 deletions tests/compiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -1700,5 +1700,43 @@

finish(done);
});

it('should allow access to outer scope in call blocks', function(done) {
render(
'{% macro inside() %}' +
'{{ caller() }}' +
'{% endmacro %}' +
'{% macro outside(var) %}' +
'{{ var }}\n' +
'{% call inside() %}' +
'{{ var }}' +
'{% endcall %}' +
'{% endmacro %}' +
'{{ outside("foobar") }}', {}, {}, function(err, res) {
expect(res.trim()).to.eql('foobar\nfoobar');
});

finish(done);
});

it('should not leak scope from call blocks to parent', function(done) {
render(
'{% set var = "expected" %}' +
'{% macro inside() %}' +
'{% set var = "incorrect-value" %}' +
'{{ caller() }}' +
'{% endmacro %}' +
'{% macro outside() %}' +
'{% call inside() %}' +
'{% endcall %}' +
'{% endmacro %}' +
'{{ outside() }}' +
'{{ var }}', {}, {}, function(err, res) {
expect(res.trim()).to.eql('expected');
});

finish(done);
});

});
})();

0 comments on commit efd2ee9

Please sign in to comment.