File: src\R.Debug.js
module.exports = function(R) {
var VError = require("verror");
var _ = require("lodash");
var assert = require("assert");
var util = require("util");
var Promise = require("bluebird");
/**
* <p>Debugging utilities embedded with R.<br />
* Provides conditionals for dev/prod mode and associated assertions to avoid lengthy try/catch blocks in prod mode.</p>
* @memberof R
* @type {Object}
* @class R.Debug
*/
var Debug = /** @lends R.Debug */{
/**
* @method _mode
* @return {String} string The basic string
* @type {String}
* @private
*/
_mode: function() {
/* If in node or envified browser environment, read from env */
if(process && process.env && process.env.NODE_ENV) {
return process.env.NODE_ENV;
}
/* Defaults to 'development'. */
else {
return 'development';
}
}(),
/**
* <p>Manually override mode to either 'production' or 'development'.<br/>
* Use this if you don't want to use envify.</p>
* @method setMode
* @param {String} mode
* @public
*/
setMode: function setMode(mode) {
assert('development' === mode || 'production' === mode, "R.Debug.setMode(...): mode should be either 'development' or 'production'.");
R.Debug._mode = mode;
if(process && process.env) {
process.env.NODE_ENV = mode;
}
if(mode === 'production') {
Debug.disableStackTracesForSetImmediate();
}
},
_vanillaSetImmediate: null,
_vanillaClearImmediate: null,
enableStackTracesForSetImmediate: function enableStackTracesForSetImmediate() {
assert(Debug.isDev(), "R.enableStackTracesForSetImmediate(...): should only be called in development mode.");
assert(R._vanillaSetImmediate !== null, "R.enableStackTracesForSetImmediate(...): already enabled.");
if(R.isClient()) {
Debug._vanillaSetImmediate = window.setImmediate;
Debug._vanillaClearImmediate = clearTimeout;
window.setImmediate = _.defer;
window.clearImmediate = clearTimeout;
}
else if(R.isServer()) {
Debug._vanillaSetImmediate = global.setImmediate;
Debug._vanillaClearImmediate = clearTimeout;
global.setImmediate = _.defer;
global.clearImmediate = clearTimeout;
}
},
disableStackTracesForSetImmediate: function disableStackTracesForSetImmediate() {
if(Debug._vanillaSetImmediate) {
window.setImmediate = Debug._vanillaSetImmediate;
}
if(Debug._vanillaClearImmediate) {
window.clearImmediate = Debug._vanillaClearImmediate;
}
},
/**
* <p> Returns a boolean describing whether the current mode is dev. </p>
* @method isDev
* @return {Boolean} boolean Truthy iff the current mode is dev.
* @public
*/
isDev: function isDev() {
return 'development' === Debug._mode;
},
/**
* <p> Returns a boolean describing whether the current mode is prod. </p>
* @method isProd
* @return {Boolean} boolean Truthy iff the current mode is prod.
* @public
*/
isProd: function isProd() {
return 'production' === Debug._mode;
},
/**
* <p>Runs a function iff the current mode is dev.</p>
* @method dev
* @param {Function} fn The function to invoke iff the current mode is dev.
* @return {*} * The return value of fn iff the current mode is dev, undefined otherwise.
* @public
*/
dev: function dev(fn) {
return Debug.isDev() ? fn() : void 0;
},
/**
* <p>Runs a function iff the current mode is prod.</p>
* @method prod
* @param {Function} fn The function to invoke iff the current mode is prod.
* @return {*} * The return value of fn iff the current mode is prod, undefined otherwise.
* @public
*/
prod: function prod(fn) {
return Debug.isProd() ? fn(): void 0;
},
/**
* <p>Returns a function iff the current mode is dev, otherwise returns a noop function.<br />
* "dev-only" maybe monad.</p>
* @method maybeDev
* @param {Function} fn The function to be returned if the current mode is dev.
* @return {Function} The original function iff the current mode is dev, no-op function otherwise.
* @public
*/
maybeDev: function maybeDev(fn) {
return Debug.isDev() ? fn : _.noop;
},
/**
* <p>Returns a function iff the current mode is prod, otherwise returns a noop function.<br />
* "prod-only" maybe monad.</p>
* @method maybeProd
* @param {Function} fn The function to be returned if the current mode is prod.
* @return {Function} The original function iff the current mode is prod, no-op function otherwise.
* @public
*/
maybeProd: function maybeProd(fn) {
return Debug.isProd() ? fn : _.noop;
},
/**
* <p>Trigger a debugger breakpoint without raising jshint errors.</p>
* @method breakpoint
* @public
*/
breakpoint: function breakpoint() {
/* jshint debug:true */
debugger;
/* jshint debug:false */
},
stackTrace: function stackTrace() {
var err = new Error();
return err.stack;
},
display: function display(name, obj) {
console.warn("++++[ " + name + " ]++++");
for(var k in obj) {
console.warn(k, ":", obj[k]);
}
console.warn("----[ " + name + " ]----");
},
fail: function fail(err) {
throw err;
},
/**
* <p>Runs assert from node core with the same arguments.<br />
* Throws if the assert fails and the current mode is dev.<br />
* console.error if the assert fails and the current mode is prod.<br />
* No side effect if the assert doesn't fail.</p>
* @method check
* @return {Boolean} Truthy only if the assert doesn't fail. False if the assert fails and not in dev mode.
* @type {Function}
* @public
*/
check: function check() {
try {
assert.apply(null, arguments);
}
catch(err) {
if(Debug.isDev()) {
Debug.fail(err);
}
else {
console.error(err);
return false;
}
}
return true;
},
/**
* <p>Extends an Error to provide additional information while preserving the error stack.<br />
* Uses VError under the hood.</p>
* @method extendError
* @param {Error} originalErr The original error.
* @param {Error|String} wrappingErr The error to use as wrapper.
* @return {Error} The new, extended Error.
* @public
*/
extendError: function extendError(err, message) {
err.message = message + ": " + err.message;
return err;
},
/**
* Returns a function that will rethrow when passed an error.
* @method rethrow
* @param {Error|String} [wrappingErr] Optionnal error to use as wrapper.
* @public
*/
rethrow: function rethrow(message) {
if(!message) {
return function(err) {
if(err) {
Debug.fail(err);
}
};
}
else {
return function(err) {
if(err) {
console.error(message);
Debug.fail(err);
}
};
}
},
};
if(Debug.isDev()) {
Debug.enableStackTracesForSetImmediate();
Promise.longStackTraces();
}
return Debug;
};