Skip to content

Commit

Permalink
Fix context-stack when calling block-helpers on null values
Browse files Browse the repository at this point in the history
Fixes #1319

Original behaviour:
- When a block-helper was called on a null-context, an empty object was used
  as context instead. (#1093)
- The runtime verifies that whether the current context equals the
  last context and adds the current context to the stack, if it is not.
  This is done, so that inside a block-helper, the ".." path can be used
  to go back to the parent element.
- If the helper is called on a "null" element, the context was added, even
  though it shouldn't be, because the "null != {}"

Fix:
- The commit replaces "null" by the identifiable "container.nullContext"
  instead of "{}". "nullContext" is a sealed empty object.
- An additional check in the runtime verifies that the context is
  only added to the stack, if it is not the nullContext.
  • Loading branch information
nknapp committed Mar 9, 2017
1 parent 84ed1f5 commit e89f03b
Show file tree
Hide file tree
Showing 3 changed files with 9 additions and 2 deletions.
2 changes: 1 addition & 1 deletion lib/handlebars/compiler/javascript-compiler.js
Expand Up @@ -910,7 +910,7 @@ JavaScriptCompiler.prototype = {
let params = [],
paramsInit = this.setupHelperArgs(name, paramSize, params, blockHelper);
let foundHelper = this.nameLookup('helpers', name, 'helper'),
callContext = this.aliasable(`${this.contextName(0)} != null ? ${this.contextName(0)} : {}`);
callContext = this.aliasable(`${this.contextName(0)} != null ? ${this.contextName(0)} : container.nullContext`);

return {
params: params,
Expand Down
4 changes: 3 additions & 1 deletion lib/handlebars/runtime.js
Expand Up @@ -121,6 +121,8 @@ export function template(templateSpec, env) {

return obj;
},
// An empty object to use as replacement for null-contexts
nullContext: Object.seal({}),

noop: env.VM.noop,
compilerInfo: templateSpec.compiler
Expand Down Expand Up @@ -174,7 +176,7 @@ 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]) {
if (depths && context != depths[0] && !(context === container.nullContext && depths[0] === null)) {
currentDepths = [context].concat(depths);
}

Expand Down
5 changes: 5 additions & 0 deletions spec/regressions.js
Expand Up @@ -288,4 +288,9 @@ describe('Regressions', function() {

shouldCompileTo('{{helpa length="foo"}}', [obj, helpers], 'foo');
});

it('GH-1319: "unless" breaks when "each" value equals "null"', function() {
var string = '{{#each list}}{{#unless ./prop}}parent={{../value}} {{/unless}}{{/each}}';
shouldCompileTo(string, { value: 'parent', list: [ null, 'a'] }, 'parent=parent parent=parent ', '');
});
});

0 comments on commit e89f03b

Please sign in to comment.