Skip to content

Commit

Permalink
Avoid depth creation when context remains the same
Browse files Browse the repository at this point in the history
Creating a new depth value seems to confuse users as they don’t expect things like `if` to require multiple `..` to break out of. With the change, we avoid pushing a context to the depth list if it’s already on the top of the stack, effectively removing cases where `.` and `..` are the same object and multiple `..` references are required.

This is a breaking change and all templates that utilize `..` will have to check their usage and confirm that this does not break desired behavior. Helper authors now need to take care to return the same context value whenever it is conceptually the same and to avoid behaviors that may execute children under the current context in some situations and under different contexts under other situations.

Fixes handlebars-lang#1028
  • Loading branch information
kpdecker committed Aug 3, 2015
1 parent 1c08771 commit 279e038
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 3 deletions.
13 changes: 11 additions & 2 deletions lib/handlebars/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,11 @@ export function template(templateSpec, env) {
let depths,
blockParams = templateSpec.useBlockParams ? [] : undefined;
if (templateSpec.useDepths) {
depths = options.depths ? [context].concat(options.depths) : [context];
if (options.depths) {
depths = context !== options.depths[0] ? [context].concat(depths) : options.depths;
} else {
depths = [context];
}
}

return templateSpec.main.call(container, context, container.helpers, container.partials, data, blockParams, depths);
Expand Down Expand Up @@ -170,12 +174,17 @@ export function template(templateSpec, env) {

export function wrapProgram(container, i, fn, data, declaredBlockParams, blockParams, depths) {
function prog(context, options = {}) {
let currentDepths = depths;
if (depths && context !== depths[0]) {
currentDepths = [context].concat(depths);
}

return fn.call(container,
context,
container.helpers, container.partials,
options.data || data,
blockParams && [options.blockParams].concat(blockParams),
depths && [context].concat(depths));
currentDepths);
}
prog.program = i;
prog.depth = depths ? depths.length : 0;
Expand Down
5 changes: 5 additions & 0 deletions spec/builtins.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ describe('builtin helpers', function() {
shouldCompileTo(string, {goodbye: function() {return this.foo; }, world: 'world'}, 'cruel world!',
'if with function does not show the contents when returns undefined');
});

it('should not change the depth list', function() {
var string = '{{#with foo}}{{#if goodbye}}GOODBYE cruel {{../world}}!{{/if}}{{/with}}';
shouldCompileTo(string, {foo: {goodbye: true}, world: 'world'}, 'GOODBYE cruel world!');
});
});

describe('#with', function() {
Expand Down
15 changes: 14 additions & 1 deletion spec/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,27 @@ describe('helpers', function() {
shouldCompileTo(string, [{}, helpers], ' {{{{b}}}} {{{{/b}}}} ', 'raw block helper should get nested raw block as raw content');
});

it('helper block with identical context', function() {
var string = '{{#goodbyes}}{{name}}{{/goodbyes}}';
var hash = {name: 'Alan'};
var helpers = {goodbyes: function(options) {
var out = '';
var byes = ['Goodbye', 'goodbye', 'GOODBYE'];
for (var i = 0, j = byes.length; i < j; i++) {
out += byes[i] + ' ' + options.fn(this) + '! ';
}
return out;
}};
shouldCompileTo(string, [hash, helpers], 'Goodbye Alan! goodbye Alan! GOODBYE Alan! ');
});
it('helper block with complex lookup expression', function() {
var string = '{{#goodbyes}}{{../name}}{{/goodbyes}}';
var hash = {name: 'Alan'};
var helpers = {goodbyes: function(options) {
var out = '';
var byes = ['Goodbye', 'goodbye', 'GOODBYE'];
for (var i = 0, j = byes.length; i < j; i++) {
out += byes[i] + ' ' + options.fn(this) + '! ';
out += byes[i] + ' ' + options.fn({}) + '! ';
}
return out;
}};
Expand Down

0 comments on commit 279e038

Please sign in to comment.