UNPKG

@google-cloud/promisify

Version:

A simple utility for promisifying functions and classes.

148 lines 5.59 kB
"use strict"; /* eslint-disable prefer-rest-params */ Object.defineProperty(exports, "__esModule", { value: true }); exports.callbackifyAll = exports.callbackify = exports.promisifyAll = exports.promisify = void 0; /** * Wraps a callback style function to conditionally return a promise. * * @param {function} originalMethod - The method to promisify. * @param {object=} options - Promise options. * @param {boolean} options.singular - Resolve the promise with single arg instead of an array. * @return {function} wrapped */ function promisify(originalMethod, options) { if (originalMethod.promisified_) { return originalMethod; } options = options || {}; const slice = Array.prototype.slice; // tslint:disable-next-line:no-any const wrapper = function () { let last; for (last = arguments.length - 1; last >= 0; last--) { const arg = arguments[last]; if (typeof arg === 'undefined') { continue; // skip trailing undefined. } if (typeof arg !== 'function') { break; // non-callback last argument found. } return originalMethod.apply(this, arguments); } // peel trailing undefined. const args = slice.call(arguments, 0, last + 1); // tslint:disable-next-line:variable-name let PromiseCtor = Promise; // Because dedupe will likely create a single install of // @google-cloud/common to be shared amongst all modules, we need to // localize it at the Service level. if (this && this.Promise) { PromiseCtor = this.Promise; } return new PromiseCtor((resolve, reject) => { // tslint:disable-next-line:no-any args.push((...args) => { const callbackArgs = slice.call(args); const err = callbackArgs.shift(); if (err) { return reject(err); } if (options.singular && callbackArgs.length === 1) { resolve(callbackArgs[0]); } else { resolve(callbackArgs); } }); originalMethod.apply(this, args); }); }; wrapper.promisified_ = true; return wrapper; } exports.promisify = promisify; /** * Promisifies certain Class methods. This will not promisify private or * streaming methods. * * @param {module:common/service} Class - Service class. * @param {object=} options - Configuration object. */ // tslint:disable-next-line:variable-name function promisifyAll(Class, options) { const exclude = (options && options.exclude) || []; const ownPropertyNames = Object.getOwnPropertyNames(Class.prototype); const methods = ownPropertyNames.filter(methodName => { // clang-format off return (!exclude.includes(methodName) && typeof Class.prototype[methodName] === 'function' && // is it a function? !/(^_|(Stream|_)|promise$)|^constructor$/.test(methodName) // is it promisable? ); // clang-format on }); methods.forEach(methodName => { const originalMethod = Class.prototype[methodName]; if (!originalMethod.promisified_) { Class.prototype[methodName] = exports.promisify(originalMethod, options); } }); } exports.promisifyAll = promisifyAll; /** * Wraps a promisy type function to conditionally call a callback function. * * @param {function} originalMethod - The method to callbackify. * @param {object=} options - Callback options. * @param {boolean} options.singular - Pass to the callback a single arg instead of an array. * @return {function} wrapped */ function callbackify(originalMethod) { if (originalMethod.callbackified_) { return originalMethod; } // tslint:disable-next-line:no-any const wrapper = function () { if (typeof arguments[arguments.length - 1] !== 'function') { return originalMethod.apply(this, arguments); } const cb = Array.prototype.pop.call(arguments); originalMethod.apply(this, arguments).then( // tslint:disable-next-line:no-any (res) => { res = Array.isArray(res) ? res : [res]; cb(null, ...res); }, (err) => cb(err)); }; wrapper.callbackified_ = true; return wrapper; } exports.callbackify = callbackify; /** * Callbackifies certain Class methods. This will not callbackify private or * streaming methods. * * @param {module:common/service} Class - Service class. * @param {object=} options - Configuration object. */ function callbackifyAll( // tslint:disable-next-line:variable-name Class, options) { const exclude = (options && options.exclude) || []; const ownPropertyNames = Object.getOwnPropertyNames(Class.prototype); const methods = ownPropertyNames.filter(methodName => { // clang-format off return (!exclude.includes(methodName) && typeof Class.prototype[methodName] === 'function' && // is it a function? !/^_|(Stream|_)|^constructor$/.test(methodName) // is it callbackifyable? ); // clang-format on }); methods.forEach(methodName => { const originalMethod = Class.prototype[methodName]; if (!originalMethod.callbackified_) { Class.prototype[methodName] = exports.callbackify(originalMethod); } }); } exports.callbackifyAll = callbackifyAll; //# sourceMappingURL=index.js.map