123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- 'use strict';
- /*
- * cls-bluebird
- * Module entry point
- */
- // Modules
- var isBluebird = require('is-bluebird');
- // Require Bluebird library
- // Ignore errors if cannot be required
- var Bluebird;
- try {
- Bluebird = require('bluebird');
- } catch (err) {}
- // Imports
- var shimMethod = require('./shimMethod'),
- shimOnCancel = require('./shimOnCancel'),
- shimCall = require('./shimCall'),
- shimUsing = require('./shimUsing'),
- shimCoroutine = require('./shimCoroutine');
- // Exports
- /**
- * Patch bluebird to run maintain CLS context for a specific namespace.
- * If a Bluebird Promise constructor is provided, it is patched.
- * If not provided, the version returned by `require('bluebird')` is used.
- *
- * @param {Object} ns - CLS namespace object
- * @param {Function} [Promise] - Bluebird Promise constructor to patch (optional)
- * @returns {Function} - Bluebird Promise constructor
- * @throws {TypeError} - If `ns` or `Promise` are not of correct type
- * @throws {Error} - If `Promise` not provided and cannot require `bluebird` module
- */
- module.exports = function patchBluebird(ns, Promise) {
- // Check namespace is valid
- if (!ns || typeof ns !== 'object' || typeof ns.bind !== 'function' || typeof ns.run !== 'function') throw new TypeError('Must provide CLS namespace to patch Bluebird against');
- // Check Promise implementation is some variation of Bluebird
- // If none provided, use default Bluebird
- if (!Promise) {
- Promise = Bluebird;
- if (!Promise) throw new Error('Could not require Bluebird');
- } else if (!isBluebird.ctor(Promise)) {
- throw new TypeError('Promise implementation provided must be Bluebird');
- }
- // Patch all methods to carry CLS context
- var v3 = isBluebird.ctor.v3(Promise);
- /*
- * Core
- *
- * Not patched as always run callback synchronously:
- * new Promise()
- * Promise.try() / Promise.attempt()
- *
- * Not patched as do not take a callback:
- * Promise.bind() / .bind()
- * Promise.resolve() / Promise.fulfilled() / Promise.cast()
- * Promise.reject() / Promise.rejected()
- *
- * Not patched as call another patched method synchronously
- * .error() - calls .catch()
- *
- * Not patched as are wrappers:
- * Promise.method()
- *
- * NB Due to bug in bluebird v2 https://github.com/petkaantonov/bluebird/issues/1153
- * `Promise.join()` calls the callback synchronously if input is only values or
- * resolved promises, but async if any promises are pending.
- * So handler is sometimes bound to CLS context unnecessarily, but this does no harm
- * beyond the very slight performance overhead of an extra `ns.bind()` call.
- */
- shimProto('then', v3 ? [0, 1] : [0, 1, 2]);
- shimProto('spread', v3 ? [0] : [0, 1]);
- shimProto('finally', [0]);
- Promise.prototype.lastly = Promise.prototype.finally;
- shimStatic('join', [-1]);
- if (!v3) {
- // Only patched in bluebird v2.
- // In bluebird v3 `.catch()` calls `.then()` immediately which binds callback.
- shimProto('catch', [-1]);
- Promise.prototype.caught = Promise.prototype.catch;
- }
- /*
- * Synchronous inspection
- *
- * Not patched as do not take a callback:
- * .isFulfilled()
- * .isRejected()
- * .isPending()
- * .isCancelled()
- * .isResolved()
- * .value()
- * .reason()
- * .reflect()
- */
- /*
- * Collections
- *
- * Not patched as do not take a callback:
- * Promise.all() / .all()
- * Promise.props() / .props()
- * Promise.any() / .any()
- * Promise.some() / .some()
- * Promise.race() / .race()
- */
- shimBoth('map', [0]);
- shimBoth('filter', [0]);
- shimBoth('reduce', [0]);
- shimBoth('each', [0]);
- // In bluebird v2, there is no `Promise.mapSeries()`/`.mapSeries()` method
- if (v3) shimBoth('mapSeries', [0]);
- /*
- * Resource management
- *
- * NB disposer callbacks are bound to context at time disposer created, not when utilized in `using()`
- */
- shimUsing(Promise, ns, v3); // shims `Promise.using()`
- shimProto('disposer', [0]);
- /*
- * Promisification
- *
- * Not patched as always run callback synchronously:
- * Promise.fromCallback()
- * Promise.fromNode()
- *
- * Not patched as they are wrappers:
- * Promise.promisify()
- * Promise.promisifyAll()
- */
- shimProto('asCallback', [0]);
- Promise.prototype.nodeify = Promise.prototype.asCallback;
- /*
- * Timers
- *
- * Not patched as do not take a callback:
- * Promise.delay() / .delay()
- * .timeout()
- */
- /*
- * Cancellation
- *
- * Not patched as does not take a callback:
- * .cancel() / .break()
- * .isCancellable()
- * .cancellable() (bluebird v2 only)
- * .uncancellable() (bluebird v2 only)
- *
- * NB In bluebird v3 `onCancel` handler will be called
- * in CLS context of call to `onCancel()`.
- */
- // Patch `Promise.prototype._resolveFromExecutor`
- // in order to patch `onCancel` handler in `new Promise()`.
- if (v3) shimOnCancel(Promise, ns);
- /*
- * Generators
- *
- * Not patched as does not take a callback:
- * Promise.coroutine.addYieldHandler()
- *
- * NB `options.yieldHandler` will run in whatever CLS context is active at time of `yield`
- */
- var addYieldHandler = Promise.coroutine.addYieldHandler;
- shimCoroutine('coroutine', Promise, ns, v3); // shims `Promise.coroutine()`
- Promise.coroutine.addYieldHandler = addYieldHandler;
- /*
- * Utility
- *
- * Not patched as do not take a callback:
- * .get()
- * .return() / .thenReturn()
- * .throw() / .thenThrow()
- * .catchReturn()
- * .catchThrow()
- * Promise.getNewLibraryCopy()
- * Promise.noConflict()
- * Promise.setScheduler()
- */
- shimProto('tap', [0]);
- if (v3) shimProto('tapCatch', [-1]);
- shimCall(Promise, ns); // shims `.call()`
- /*
- * Configuration
- *
- * Not patched as do not take a callback:
- * Promise.config()
- * .suppressUnhandledRejections()
- * Promise.longStackTraces()
- * Promise.hasLongStackTraces()
- *
- * Not patched as meaningless to do so:
- * Promise.onPossiblyUnhandledRejection()
- * Promise.onUnhandledRejectionHandled()
- *
- * NB Error handlers will run with unknown CLS context.
- * CLS context should not be relied upon to be the context at the time error was thrown.
- * Catch errors with `.catch()` instead!
- */
- shimProto('done', v3 ? [0, 1] : [0, 1, 2]);
- /*
- * Progression (bluebird v2 only)
- */
- if (!v3) shimProto('progressed', [0]);
- /*
- * Undocumented
- *
- * Not patched as do not take a callback:
- * Promise.is()
- * Promise.settle() / .settle()
- * Promise.defer() / Promise.pending()
- * .toString()
- * .toJSON()
- */
- // `.fork()` does not exist in bluebird v3
- if (!v3) shimProto('fork', [0, 1, 2]);
- shimCoroutine('spawn', Promise, ns, v3); // shims `Promise.spawn()`
- // Return patched Bluebird constructor
- return Promise;
- /*
- * Patching functions
- */
- function shimStatic(methodName, args) {
- shimMethod(Promise, methodName, args, ns);
- }
- function shimProto(methodName, args) {
- shimMethod(Promise.prototype, methodName, args, ns);
- }
- function shimBoth(methodName, args) {
- shimProto(methodName, args);
- shimStatic(methodName, args.map(function(arg) { return arg < 0 ? arg : arg + 1; }));
- }
- };
|