index.js
function hybrid(fn, cb) {
	if (typeof cb === 'function') { // Already in callback style - wrap the function so that cb gets called when it completes
		return function() {
			var args = Array.prototype.slice.call(arguments, 0);
			fn.apply(this, [cb].concat(args));
		};
	} else { // Wrap the function in a promise
		return function() {
			var args = Array.prototype.slice.call(arguments, 0);
			return new Promise(function(resolve, reject) {
				fn.apply(this, [
					function(err, res) {
						if (err) {
							reject(err);
						} else {
							resolve(res);
						}
					}
				].concat(args));
			});
		};
	}
}
function hybrid(fn, cb) {
	if (typeof cb === 'function') { // Already in callback style - wrap the function so that cb gets called when it completes
		return function() {
			var args = Array.prototype.slice.call(arguments, 0);
			fn.apply(this, [cb].concat(args));
		};
	} else { // Wrap the function in a promise
		return function() {
			var args = Array.prototype.slice.call(arguments, 0);
			return new Promise(function(resolve, reject) {
				fn.apply(this, [
					function(err, res) {
						if (err) {
							reject(err);
						} else {
							resolve(res);
						}
					}
				].concat(args));
			});
		};
	}
}
Take a callback style function and return a hybrid (callback OR promise) wrapper
@param {function} fn The function to transform
@param {function} [finish] The callback to optionally call when done
@return {function} The hybrid function which runs as a callback but could accept promises

@example Transform a callback-style function into a promise
async.hybrid((done, path) => fs.stat(path, done), '/').then(stats => console.log('Stats are', stats))

@example Copy a callback-style function into another
asyncChainable.hybrid((done, path) => fs.stat(path, done), (err, stats) => console.log('Stats are', stats))