From b0578b6c94e174df0f4434c21ded2b76d2cff453 Mon Sep 17 00:00:00 2001 From: Forbes Lindesay Date: Mon, 7 Jan 2013 23:06:32 +0000 Subject: [PATCH] Handle synchronous exceptions better --- lib/consolidate.js | 315 +++++++++++++++++++-------------------------- 1 file changed, 131 insertions(+), 184 deletions(-) diff --git a/lib/consolidate.js b/lib/consolidate.js index 3f664ad..7421226 100644 --- a/lib/consolidate.js +++ b/lib/consolidate.js @@ -148,11 +148,38 @@ function fromStringRenderer(name) { }; } +/** + * Convert a function that may throw syncronous errors into a well behaved async + * function that calls it's callback exactly once. + * + * @param {Function} fn + * @return {Function} + * @api private + */ +function handleErrors(fn) { + return function (str, options, cb) { + var finished = false; + function safeCB(err, res) { + if (!finished) { + finished = true; + cb(err, res); + } else if (err) { + throw err; + } + } + try { + fn(str, options, safeCB); + } catch (ex) { + safeCB(ex); + } + }; +} + /** * Jade support. */ -exports.jade = function(path, options, fn){ +exports.jade = handleErrors(function(path, options, fn){ var engine = requires.jade; if (!engine) { try { @@ -162,13 +189,13 @@ exports.jade = function(path, options, fn){ } } engine.renderFile(path, options, fn); -}; +}); /** * Jade string support. */ -exports.jade.render = function(str, options, fn){ +exports.jade.render = handleErrors(function(str, options, fn){ var engine = requires.jade; if (!engine) { try { @@ -178,7 +205,7 @@ exports.jade.render = function(str, options, fn){ } } engine.render(str, options, fn); -}; +}); /** * Dust support. @@ -190,7 +217,7 @@ exports.dust = fromStringRenderer('dust'); * Dust string support. */ -exports.dust.render = function(str, options, fn){ +exports.dust.render = handleErrors(function(str, options, fn){ var engine = requires.dust; if (!engine) { try { @@ -215,13 +242,9 @@ exports.dust.render = function(str, options, fn){ read(path, options, callback); }; - try { - var tmpl = cache(options) || cache(options, engine.compileFn(str)); - tmpl(options, fn); - } catch (err) { - fn(err); - } -}; + var tmpl = cache(options) || cache(options, engine.compileFn(str)); + tmpl(options, fn); +}); /** * Swig support. @@ -233,15 +256,11 @@ exports.swig = fromStringRenderer('swig'); * Swig string support. */ -exports.swig.render = function(str, options, fn){ +exports.swig.render = handleErrors(function(str, options, fn){ var engine = requires.swig || (requires.swig = require('swig')); - try { - var tmpl = cache(options) || cache(options, engine.compile(str, options)); - fn(null, tmpl(options)); - } catch (err) { - fn(err); - } -}; + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl(options)); +}); /** * Atpl support. @@ -253,15 +272,11 @@ exports.atpl = fromStringRenderer('atpl'); * Atpl string support. */ -exports.atpl.render = function(str, options, fn){ +exports.atpl.render = handleErrors(function(str, options, fn){ var engine = requires.atpl || (requires.atpl = require('atpl')); - try { - var tmpl = cache(options) || cache(options, engine.compile(str, options)); - fn(null, tmpl(options)); - } catch (err) { - fn(err); - } -}; + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl(options)); +}); /** * Liquor support, @@ -273,15 +288,11 @@ exports.liquor = fromStringRenderer('liquor'); * Liquor string support. */ -exports.liquor.render = function(str, options, fn){ +exports.liquor.render = handleErrors(function(str, options, fn){ var engine = requires.liquor || (requires.liquor = require('liquor')); - try { - var tmpl = cache(options) || cache(options, engine.compile(str, options)); - fn(null, tmpl(options)); - } catch (err) { - fn(err); - } -}; + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl(options)); +}); /** * EJS support. @@ -293,15 +304,11 @@ exports.ejs = fromStringRenderer('ejs'); * EJS string support. */ -exports.ejs.render = function(str, options, fn){ +exports.ejs.render = handleErrors(function(str, options, fn){ var engine = requires.ejs || (requires.ejs = require('ejs')); - try { - var tmpl = cache(options) || cache(options, engine.compile(str, options)); - fn(null, tmpl(options)); - } catch (err) { - fn(err); - } -}; + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl(options)); +}); /** @@ -314,14 +321,10 @@ exports.eco = fromStringRenderer('eco'); * Eco string support. */ -exports.eco.render = function(str, options, fn){ +exports.eco.render = handleErrors(function(str, options, fn){ var engine = requires.eco || (requires.eco = require('eco')); - try { - fn(null, engine.render(str, options)); - } catch (err) { - fn(err); - } -}; + fn(null, engine.render(str, options)); +}); /** * Jazz support. @@ -333,17 +336,13 @@ exports.jazz = fromStringRenderer('jazz'); * Jazz string support. */ -exports.jazz.render = function(str, options, fn){ +exports.jazz.render = handleErrors(function(str, options, fn){ var engine = requires.jazz || (requires.jazz = require('jazz')); - try { - var tmpl = cache(options) || cache(options, engine.compile(str, options)); - tmpl.eval(options, function(str){ - fn(null, str); - }); - } catch (err) { - fn(err); - } -}; + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + tmpl.eval(options, function(str){ + fn(null, str); + }); +}); /** * JQTPL support. @@ -355,15 +354,11 @@ exports.jqtpl = fromStringRenderer('jqtpl'); * JQTPL string support. */ -exports.jqtpl.render = function(str, options, fn){ +exports.jqtpl.render = handleErrors(function(str, options, fn){ var engine = requires.jqtpl || (requires.jqtpl = require('jqtpl')); - try { - engine.template(str, str); - fn(null, engine.tmpl(str, options)); - } catch (err) { - fn(err); - } -}; + engine.template(str, str); + fn(null, engine.tmpl(str, options)); +}); /** * Haml support. @@ -375,37 +370,29 @@ exports.haml = fromStringRenderer('haml'); * Haml string support. */ -exports.haml.render = function(str, options, fn){ +exports.haml.render = handleErrors(function(str, options, fn){ var engine = requires.hamljs || (requires.hamljs = require('hamljs')); - try { - options.locals = options; - fn(null, engine.render(str, options).trimLeft()); - } catch (err) { - fn(err); - } -}; + options.locals = options; + fn(null, engine.render(str, options).trimLeft()); +}); /** * Whiskers support. */ -exports.whiskers = function(path, options, fn){ +exports.whiskers = handleErrors(function(path, options, fn){ var engine = requires.whiskers || (requires.whiskers = require('whiskers')); engine.__express(path, options, fn); -}; +}); /** * Whiskers string support. */ -exports.whiskers.render = function(str, options, fn){ +exports.whiskers.render = handleErrors(function(str, options, fn){ var engine = requires.whiskers || (requires.whiskers = require('whiskers')); - try { - fn(null, engine.render(str, options)); - } catch (err) { - fn(err); - } -}; + fn(null, engine.render(str, options)); +}); /** * Coffee-HAML support. @@ -417,15 +404,11 @@ exports['haml-coffee'] = fromStringRenderer('haml-coffee'); * Coffee-HAML string support. */ -exports['haml-coffee'].render = function(str, options, fn){ +exports['haml-coffee'].render = handleErrors(function(str, options, fn){ var engine = requires.HAMLCoffee || (requires.HAMLCoffee = require('haml-coffee')); - try { - var tmpl = cache(options) || cache(options, engine.compile(str, options)); - fn(null, tmpl(options)); - } catch (err) { - fn(err); - } -}; + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl(options)); +}); /** * Hogan support. @@ -437,15 +420,11 @@ exports.hogan = fromStringRenderer('hogan'); * Hogan string support. */ -exports.hogan.render = function(str, options, fn){ +exports.hogan.render = handleErrors(function(str, options, fn){ var engine = requires.hogan || (requires.hogan = require('hogan.js')); - try { - var tmpl = cache(options) || cache(options, engine.compile(str, options)); - fn(null, tmpl.render(options, options.partials)); - } catch (err) { - fn(err); - } -}; + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl.render(options, options.partials)); +}); /** * Handlebars support. @@ -457,18 +436,14 @@ exports.handlebars = fromStringRenderer('handlebars'); * Handlebars string support. */ -exports.handlebars.render = function(str, options, fn) { +exports.handlebars.render = handleErrors(function(str, options, fn) { var engine = requires.handlebars || (requires.handlebars = require('handlebars')); - try { - for (var partial in options.partials) { - engine.registerPartial(partial, options.partials[partial]); - } - var tmpl = cache(options) || cache(options, engine.compile(str, options)); - fn(null, tmpl(options)); - } catch (err) { - fn(err); + for (var partial in options.partials) { + engine.registerPartial(partial, options.partials[partial]); } -} + var tmpl = cache(options) || cache(options, engine.compile(str, options)); + fn(null, tmpl(options)); +}); /** * Underscore support. @@ -480,50 +455,38 @@ exports.underscore = fromStringRenderer('underscore'); * Underscore string support. */ -exports.underscore.render = function(str, options, fn) { +exports.underscore.render = handleErrors(function(str, options, fn) { var engine = requires.underscore || (requires.underscore = require('underscore')); - try { - var tmpl = cache(options) || cache(options, engine.template(str, null, options)); - fn(null, tmpl(options).replace(/\n$/, '')); - } catch (err) { - fn(err); - } -}; + var tmpl = cache(options) || cache(options, engine.template(str, null, options)); + fn(null, tmpl(options).replace(/\n$/, '')); +}); /** * QEJS support. */ -exports.qejs = function (path, options, fn) { - try { - var engine = requires.qejs || (requires.qejs = require('qejs')); - engine.renderFile(path, options).then(function (result) { - fn(null, result); - }, function (err) { - fn(err); - }).end(); - } catch (err) { - fn(err); - } -}; +exports.qejs = handleErrors(function (path, options, fn) { + var engine = requires.qejs || (requires.qejs = require('qejs')); + engine.renderFile(path, options).then(function (result) { + fn(null, result); + }, function (err) { + fn(err); + }).end(); +}); /** * QEJS string support. */ -exports.qejs.render = function (str, options, fn) { - try { - var engine = requires.qejs || (requires.qejs = require('qejs')); - engine.render(str, options).then(function (result) { - fn(null, result); - }, function (err) { - fn(err); - }).end(); - } catch (err) { - fn(err); - } -}; +exports.qejs.render = handleErrors(function (str, options, fn) { + var engine = requires.qejs || (requires.qejs = require('qejs')); + engine.render(str, options).then(function (result) { + fn(null, result); + }, function (err) { + fn(err); + }).end(); +}); /** @@ -536,15 +499,11 @@ exports.walrus = fromStringRenderer('walrus'); * Walrus string support. */ -exports.walrus.render = function (str, options, fn) { +exports.walrus.render = handleErrors(function (str, options, fn) { var engine = requires.walrus || (requires.walrus = require('walrus')); - try { - var tmpl = cache(options) || cache(options, engine.parse(str)); - fn(null, tmpl.compile(options)); - } catch (err) { - fn(err); - } -}; + var tmpl = cache(options) || cache(options, engine.parse(str)); + fn(null, tmpl.compile(options)); +}); /** * Mustache support. @@ -556,20 +515,16 @@ exports.mustache = fromStringRenderer('mustache'); * Mustache string support. */ -exports.mustache.render = function(str, options, fn) { +exports.mustache.render = handleErrors(function(str, options, fn) { var engine = requires.mustache || (requires.mustache = require('mustache')); - try { - fn(null, engine.to_html(str, options, options.partials)); - } catch (err) { - fn(err); - } -}; + fn(null, engine.to_html(str, options, options.partials)); +}); /** * Just support. */ -exports.just = function(path, options, fn){ +exports.just = handleErrors(function(path, options, fn){ var engine = requires.just; if (!engine) { var JUST = require('just'); @@ -577,23 +532,23 @@ exports.just = function(path, options, fn){ } engine.configure({ useCache: options.cache }); engine.render(path, options, fn); -}; +}); /** * Just string support. */ -exports.just.render = function(str, options, fn){ +exports.just.render = handleErrors(function(str, options, fn){ var JUST = require('just'); var engine = new JUST({ root: { page: str }}); engine.render('page', options, fn); -}; +}); /** * ECT support. */ -exports.ect = function(path, options, fn){ +exports.ect = handleErrors(function(path, options, fn){ var engine = requires.ect; if (!engine) { var ECT = require('ect'); @@ -601,17 +556,17 @@ exports.ect = function(path, options, fn){ } engine.configure({ cache: options.cache }); engine.render(path, options, fn); -}; +}); /** * ECT string support. */ -exports.ect.render = function(str, options, fn){ +exports.ect.render = handleErrors(function(str, options, fn){ var ECT = require('ect'); var engine = new ECT({ root: { page: str }}); engine.render('page', options, fn); -}; +}); /** * mote support. @@ -623,34 +578,26 @@ exports.mote = fromStringRenderer('mote'); * mote string support. */ -exports.mote.render = function(str, options, fn){ +exports.mote.render = handleErrors(function(str, options, fn){ var engine = requires.mote || (requires.mote = require('mote')); - try { - var tmpl = cache(options) || cache(options, engine.compile(str)); - fn(null, tmpl(options)); - } catch (err) { - fn(err); - } -}; + var tmpl = cache(options) || cache(options, engine.compile(str)); + fn(null, tmpl(options)); +}); /** * Toffee support. */ -exports.toffee = function(path, options, fn){ +exports.toffee = handleErrors(function(path, options, fn){ var toffee = requires.toffee || (requires.toffee = require('toffee')); toffee.__consolidate_engine_render(path, options, fn); -}; +}); /** * Toffee string support. */ -exports.toffee.render = function(str, options, fn) { +exports.toffee.render = handleErrors(function(str, options, fn) { var engine = requires.toffee || (requires.toffee = require('toffee')); - try { - engine.str_render(str, options,fn); - } catch (err) { - fn(err); - } -} + engine.str_render(str, options,fn); +});