'use strict'; const promisify = require('./promisify'); const skipMap = { constructor: true, arity: true, length: true, name: true, arguments: true, caller: true, callee: true, prototype: true, __isPromisified__: true }; module.exports = promisifyAll; /** * @param {Object} target * @param {Object} [opts] * @param {String} [opts.suffix=Async] * @param {Function} [opts.filter] * @param {Integer} [opts.depth=2] * @example * const redis = require('redis'); * Aigle.promisifyAll(redis); * const client = redis.createClient(); * * const key = 'test'; * redis.hsetAsync(key, 1) * .then(() => redis.hgetAsync(key)) * .then(value => console.log(value)); // 1 */ function promisifyAll(target, opts) { const { suffix = 'Async', filter = defaultFilter, depth = 2 } = opts || {}; _promisifyAll(suffix, filter, target, undefined, undefined, depth); return target; } function defaultFilter(name) { return /^(?!_).*/.test(name); } function _promisifyAll(suffix, filter, obj, key, target, depth) { const memo = {}; switch (typeof obj) { case 'function': if (target) { if (obj.__isPromisified__) { return; } const _key = `${key}${suffix}`; if (target[_key]) { if (!target[_key].__isPromisified__) { throw new TypeError( `Cannot promisify an API that has normal methods with '${suffix}'-suffix` ); } } else { target[_key] = promisify(obj); } } iterate(suffix, filter, obj, obj, depth, memo); iterate(suffix, filter, obj.prototype, obj.prototype, depth, memo); break; case 'object': if (!obj) { break; } iterate(suffix, filter, obj, obj, depth, memo); iterate(suffix, filter, Object.getPrototypeOf(obj), obj, depth, memo); } } const fp = Function.prototype; const op = Object.prototype; const ap = Array.prototype; function iterate(suffix, filter, obj, target, depth, memo) { if (depth-- === 0 || !obj || fp === obj || op === obj || ap === obj || Object.isFrozen(obj)) { return; } const keys = Object.getOwnPropertyNames(obj); let l = keys.length; while (l--) { const key = keys[l]; if (skipMap[key] === true || memo[key] === true || !filter(key)) { continue; } const desc = Object.getOwnPropertyDescriptor(obj, key); if (!desc || desc.set || desc.get) { continue; } memo[key] = true; _promisifyAll(suffix, filter, obj[key], key, target, depth); } }