Catch exceptions thrown from template helpers

This commit is contained in:
David Greenspan
2014-07-02 20:44:14 -07:00
parent ff0a819ace
commit 34d30f52ce
3 changed files with 24 additions and 11 deletions

View File

@@ -1,11 +1,6 @@
// XXX This is dead code but we should probably still do something like this.
// Change "Meteor UI" to "Blaze". Actually, "Exception in Blaze" is cryptic
// and misleading; better to make it clear the fault is in user code, as in
// "Exception in 'created' callback" etc.
var debugFunc;
// Meteor UI calls into user code in many places, and it's nice to catch exceptions
// We call into user code in many places, and it's nice to catch exceptions
// propagated from user code immediately so that the whole system doesn't just
// break. Catching exceptions is easy; reporting them is hard. This helper
// reports exceptions.
@@ -22,7 +17,7 @@ var debugFunc;
//
// An optional second argument overrides the default message.
reportUIException = function (e, msg) {
Blaze.reportException = function (e, msg) {
if (! debugFunc)
// adapted from Deps
debugFunc = function () {
@@ -34,5 +29,18 @@ reportUIException = function (e, msg) {
// In Chrome, `e.stack` is a multiline string that starts with the message
// and contains a stack trace. Furthermore, `console.log` makes it clickable.
// `console.log` supplies the space between the two arguments.
debugFunc()(msg || 'Exception in Meteor UI:', e.stack || e.message);
debugFunc()(msg || 'Exception caught in template:', e.stack || e.message);
};
Blaze.wrapCatchingExceptions = function (f, where) {
if (typeof f !== 'function')
return f;
return function () {
try {
return f.apply(this, arguments);
} catch (e) {
Blaze.reportException(e, 'Exception in ' + where + ':');
}
};
};

View File

@@ -18,6 +18,10 @@ var bindToCurrentDataIfIsFunction = function (x) {
return x;
};
var wrapHelper = function (f) {
return Blaze.wrapCatchingExceptions(f, 'template helper');
};
// Implements {{foo}} where `name` is "foo"
// and `component` is the component the tag is found in
// (the lexical "self," on which to look for methods).
@@ -37,15 +41,15 @@ Blaze.View.prototype.lookup = function (name, _options) {
return Blaze._parentData(name.length - 1);
} else if (template && (name in template)) {
return bindToCurrentDataIfIsFunction(template[name]);
return wrapHelper(bindToCurrentDataIfIsFunction(template[name]));
} else if (lookupTemplate && Template.__lookup__(name)) {
return Template.__lookup__(name);
} else if (UI._globalHelpers[name]) {
return bindToCurrentDataIfIsFunction(UI._globalHelpers[name]);
return wrapHelper(bindToCurrentDataIfIsFunction(UI._globalHelpers[name]));
} else {
var data = Blaze.getCurrentData();
if (data)
return bindIfIsFunction(data[name], data);
return wrapHelper(bindIfIsFunction(data[name], data));
}
return null;
};

View File

@@ -27,6 +27,7 @@ Package.on_use(function (api) {
// client and server
api.add_files([
'exceptions.js',
'reactivevar.js',
'view.js',
'builtins.js',