hybridables/try-catch-callback

View on GitHub
index.js

Summary

Maintainability
A
55 mins
Test Coverage
/*!
 * try-catch-callback <https://github.com/hybridables/try-catch-callback>
 *
 * Copyright (c) 2016 Charlike Mike Reagent <@tunnckoCore> (http://www.tunnckocore.tk)
 * Released under the MIT license.
 */

'use strict'

var extend = require('extend-shallow')

/**
 * > Pass a synchronous `fn` that returns some
 * result and handle completion or errors in `cb`
 * if given, otherwise it returns thunk which accepts
 * that `cb`. It's possible to not work in "async mode",
 * if that's the case try to use [try-catch-core][] for
 * your case, which guarantees that `cb` is called only
 * once and always in next tick, using [dezalgo][] and [once][].
 *
 * **Example**
 *
 * ```js
 * var tryCatch = require('try-catch-callback')
 *
 * tryCatch(function () {
 *   return 'fox qux'
 * }, function done (err, res) {
 *   if (err) return console.error(err)
 *   console.log(res) // => 'fox qux'
 * })
 * ```
 *
 * @param  {Function} `<fn>` function to be called.
 * @param  {Object} `[opts]` optional options, such as `context` and `args`
 * @param  {Object} `[opts.context]` context to be passed to `fn`
 * @param  {Array} `[opts.args]` custom argument(s) to be pass to `fn`, given value is arrayified
 * @param  {Boolean} `[opts.passCallback]` pass `true` if you want `cb` to be passed to `fn` args
 * @param  {Boolean} `[opts.return]` if `true` returns error/value and does not calls `cb`
 * @param  {Function} `[cb]` callback with `cb(err, res)` signature.
 * @return {Function} `thunk` if `cb` not given.
 * @throws {TypError} if `fn` not a function.
 * @throws {TypError} if no function is passed to `thunk`.
 * @api public
 */

module.exports = function tryCatchCallback (fn, opts, cb) {
  if (typeof fn !== 'function') {
    throw new TypeError('try-catch-callback: expect `fn` to be a function')
  }
  if (typeof opts === 'function') {
    cb = opts
    opts = false
  }
  opts = extend({}, opts)

  if (opts.return || typeof cb === 'function') {
    return tryCatch.call(this, fn, opts, cb)
  }
  return function thunk (done) {
    opts.thunk = true
    tryCatch.call(this, fn, opts, done)
  }
}

function tryCatch (fn, opts, cb) {
  if (opts.thunk && typeof cb !== 'function') {
    throw new TypeError('try-catch-callback: expect `cb` to be a function')
  }
  var args = arrayify(opts.args)
  var ctx = opts.context || this
  var ret = null

  try {
    ret = fn.apply(ctx, opts.passCallback ? args.concat(cb) : args)
  } catch (err) {
    return opts.return ? err : cb(err)
  }

  if (opts.return) return ret
  if (!opts.passCallback) cb(null, ret)
}

function arrayify (val) {
  if (!val) return []
  if (Array.isArray(val)) return val
  return [val]
}