Skip to content

Commit

Permalink
do not break on precompiled templates from Handlebars >=4.0.0 <4.3.0
Browse files Browse the repository at this point in the history
- The version-range above have compiler version 7 and
  precompiled templates expecte the (block)
  HelperMissing-functions in "helpers" and not in "container.hooks".
- Handlebars now accepts precompiled templates of version 7.
- If a precompiled template with version 7 is loaded,
  the (block)HelperMissing-functions are kept in "helpers"
  • Loading branch information
nknapp committed Sep 24, 2019
1 parent 64ecb9e commit 1266838
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 16 deletions.
1 change: 1 addition & 0 deletions lib/handlebars/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import logger from './logger';

export const VERSION = '4.3.0';
export const COMPILER_REVISION = 8;
export const LAST_COMPATIBLE_COMPILER_REVISION = 7;

export const REVISION_CHANGES = {
1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
Expand Down
36 changes: 21 additions & 15 deletions lib/handlebars/runtime.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
import * as Utils from './utils';
import Exception from './exception';
import {COMPILER_REVISION, createFrame, REVISION_CHANGES} from './base';
import {COMPILER_REVISION, createFrame, LAST_COMPATIBLE_COMPILER_REVISION, REVISION_CHANGES} from './base';
import {moveHelperToHooks} from './helpers';

export function checkRevision(compilerInfo) {
const compilerRevision = compilerInfo && compilerInfo[0] || 1,
currentRevision = COMPILER_REVISION;

if (compilerRevision !== currentRevision) {
if (compilerRevision < currentRevision) {
const runtimeVersions = REVISION_CHANGES[currentRevision],
compilerVersions = REVISION_CHANGES[compilerRevision];
throw new Exception('Template was precompiled with an older version of Handlebars than the current runtime. ' +
'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').');
} else {
// Use the embedded version info since the runtime doesn't know about this revision yet
throw new Exception('Template was precompiled with a newer version of Handlebars than the current runtime. ' +
'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
}
if (compilerRevision >= LAST_COMPATIBLE_COMPILER_REVISION && compilerRevision <= COMPILER_REVISION) {
return;
}

if (compilerRevision < LAST_COMPATIBLE_COMPILER_REVISION) {
const runtimeVersions = REVISION_CHANGES[currentRevision],
compilerVersions = REVISION_CHANGES[compilerRevision];
throw new Exception('Template was precompiled with an older version of Handlebars than the current runtime. ' +
'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').');
} else {
// Use the embedded version info since the runtime doesn't know about this revision yet
throw new Exception('Template was precompiled with a newer version of Handlebars than the current runtime. ' +
'Please update your runtime to a newer version (' + compilerInfo[1] + ').');
}
}

Expand All @@ -37,6 +39,9 @@ export function template(templateSpec, env) {
// for external users to override these as pseudo-supported APIs.
env.VM.checkRevision(templateSpec.compiler);

// backwards compatibility for precompiled templates with compiler-version 7 (<4.3.0)
const templateWasPrecompiledWithCompilerV7 = templateSpec.compiler && templateSpec.compiler[0] === 7;

function invokePartialWrapper(partial, context, options) {
if (options.hash) {
context = Utils.extend({}, context, options.hash);
Expand Down Expand Up @@ -163,9 +168,10 @@ export function template(templateSpec, env) {
}

container.hooks = {};
let keepHelper = options.allowCallsToHelperMissing;
moveHelperToHooks(container, 'helperMissing', keepHelper);
moveHelperToHooks(container, 'blockHelperMissing', keepHelper);

let keepHelperInHelpers = options.allowCallsToHelperMissing || templateWasPrecompiledWithCompilerV7;
moveHelperToHooks(container, 'helperMissing', keepHelperInHelpers);
moveHelperToHooks(container, 'blockHelperMissing', keepHelperInHelpers);

} else {
container.helpers = options.helpers;
Expand Down
32 changes: 32 additions & 0 deletions spec/regressions.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,4 +291,36 @@ describe('Regressions', function() {
};
shouldCompileToWithPartials(string, [{}, {}, partials], true, 'template block partial block template');
});

describe('GH-1561: 4.3.x should still work with precompiled templates from 4.0.0 <= x < 4.3.0', function() {

it('should compile and execute templates', function() {
var newHandlebarsInstance = Handlebars.create();

registerTemplate(newHandlebarsInstance);
newHandlebarsInstance.registerHelper('loud', function(value) {
return value.toUpperCase();
});
let result = newHandlebarsInstance.templates['test.hbs']({name: 'yehuda'});
equals(result.trim(), 'YEHUDA');
});

it('should call "helperMissing" if a helper is missing', function() {
var newHandlebarsInstance = Handlebars.create();

shouldThrow(() => {
registerTemplate(newHandlebarsInstance);
newHandlebarsInstance.templates['test.hbs']({});
}, Handlebars.Exception, 'Missing helper: "loud"');
});

// This is a only slightly modified precompiled templated from compiled with 4.2.1
function registerTemplate(Handlebars) {
var template = Handlebars.template, templates = Handlebars.templates = Handlebars.templates || {};
templates['test.hbs'] = template({'compiler': [7, '>= 4.0.0'], 'main': function(container, depth0, helpers, partials, data) {
return container.escapeExpression((helpers.loud || (depth0 && depth0.loud) || helpers.helperMissing).call(depth0 != null ? depth0 : (container.nullContext || {}), (depth0 != null ? depth0.name : depth0), {'name': 'loud', 'hash': {}, 'data': data}))
+ '\n\n';
}, 'useData': true});
}
});
});
2 changes: 1 addition & 1 deletion spec/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('runtime', function() {
shouldThrow(function() {
Handlebars.template({
main: {},
compiler: [Handlebars.COMPILER_REVISION - 1]
compiler: [Handlebars.LAST_COMPATIBLE_COMPILER_REVISION - 1]
});
}, Error, /Template was precompiled with an older version of Handlebars than the current runtime/);
shouldThrow(function() {
Expand Down

0 comments on commit 1266838

Please sign in to comment.