do not break on precompiled templates from Handlebars >=4.0.0 <4.3.0

- 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"
This commit is contained in:
Nils Knappmeier
2019-09-24 23:45:09 +02:00
parent 64ecb9ea84
commit 1266838829
4 changed files with 55 additions and 16 deletions
+1
View File
@@ -6,6 +6,7 @@ import logger from './logger';
export const VERSION = '4.3.0'; export const VERSION = '4.3.0';
export const COMPILER_REVISION = 8; export const COMPILER_REVISION = 8;
export const LAST_COMPATIBLE_COMPILER_REVISION = 7;
export const REVISION_CHANGES = { export const REVISION_CHANGES = {
1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it
+21 -15
View File
@@ -1,23 +1,25 @@
import * as Utils from './utils'; import * as Utils from './utils';
import Exception from './exception'; 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'; import {moveHelperToHooks} from './helpers';
export function checkRevision(compilerInfo) { export function checkRevision(compilerInfo) {
const compilerRevision = compilerInfo && compilerInfo[0] || 1, const compilerRevision = compilerInfo && compilerInfo[0] || 1,
currentRevision = COMPILER_REVISION; currentRevision = COMPILER_REVISION;
if (compilerRevision !== currentRevision) { if (compilerRevision >= LAST_COMPATIBLE_COMPILER_REVISION && compilerRevision <= COMPILER_REVISION) {
if (compilerRevision < currentRevision) { return;
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. ' + if (compilerRevision < LAST_COMPATIBLE_COMPILER_REVISION) {
'Please update your precompiler to a newer version (' + runtimeVersions + ') or downgrade your runtime to an older version (' + compilerVersions + ').'); const runtimeVersions = REVISION_CHANGES[currentRevision],
} else { compilerVersions = REVISION_CHANGES[compilerRevision];
// Use the embedded version info since the runtime doesn't know about this revision yet throw new Exception('Template was precompiled with an older version of Handlebars than the current runtime. ' +
throw new Exception('Template was precompiled with a newer 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 + ').');
'Please update your runtime to a newer version (' + compilerInfo[1] + ').'); } 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] + ').');
} }
} }
@@ -37,6 +39,9 @@ export function template(templateSpec, env) {
// for external users to override these as pseudo-supported APIs. // for external users to override these as pseudo-supported APIs.
env.VM.checkRevision(templateSpec.compiler); 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) { function invokePartialWrapper(partial, context, options) {
if (options.hash) { if (options.hash) {
context = Utils.extend({}, context, options.hash); context = Utils.extend({}, context, options.hash);
@@ -163,9 +168,10 @@ export function template(templateSpec, env) {
} }
container.hooks = {}; container.hooks = {};
let keepHelper = options.allowCallsToHelperMissing;
moveHelperToHooks(container, 'helperMissing', keepHelper); let keepHelperInHelpers = options.allowCallsToHelperMissing || templateWasPrecompiledWithCompilerV7;
moveHelperToHooks(container, 'blockHelperMissing', keepHelper); moveHelperToHooks(container, 'helperMissing', keepHelperInHelpers);
moveHelperToHooks(container, 'blockHelperMissing', keepHelperInHelpers);
} else { } else {
container.helpers = options.helpers; container.helpers = options.helpers;
+32
View File
@@ -291,4 +291,36 @@ describe('Regressions', function() {
}; };
shouldCompileToWithPartials(string, [{}, {}, partials], true, 'template block partial block template'); 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});
}
});
}); });
+1 -1
View File
@@ -21,7 +21,7 @@ describe('runtime', function() {
shouldThrow(function() { shouldThrow(function() {
Handlebars.template({ Handlebars.template({
main: {}, 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/); }, Error, /Template was precompiled with an older version of Handlebars than the current runtime/);
shouldThrow(function() { shouldThrow(function() {