init source

This commit is contained in:
Le Viet
2022-03-07 22:07:57 +07:00
parent e4376f3777
commit 8aba590a8d
11240 changed files with 1012977 additions and 0 deletions
+142
View File
@@ -0,0 +1,142 @@
# continuation-local-storage support for bluebird promises
[![NPM version](https://img.shields.io/npm/v/cls-bluebird.svg)](https://www.npmjs.com/package/cls-bluebird)
[![Build Status](https://img.shields.io/travis/TimBeyer/cls-bluebird/master.svg)](http://travis-ci.org/TimBeyer/cls-bluebird)
[![Dependency Status](https://img.shields.io/david/TimBeyer/cls-bluebird.svg)](https://david-dm.org/TimBeyer/cls-bluebird)
[![Dev dependency Status](https://img.shields.io/david/dev/TimBeyer/cls-bluebird.svg)](https://david-dm.org/TimBeyer/cls-bluebird)
[![Coverage Status](https://img.shields.io/coveralls/TimBeyer/cls-bluebird/master.svg)](https://coveralls.io/r/TimBeyer/cls-bluebird)
Patch [bluebird](https://www.npmjs.com/package/bluebird) for [continuation-local-storage](https://www.npmjs.com/package/continuation-local-storage) support.
## Current Status
Version 2.x of cls-bluebird is a complete re-write aiming to make it 100% reliable and robust. Features comprehensive test coverage (over 100,000 tests) which cover pretty much all conceivable cases.
Compatible with [bluebird](https://www.npmjs.com/package/bluebird) v2.x and v3.x. Tests cover both versions.
Please use with latest version of [bluebird](https://www.npmjs.com/package/bluebird) in either v2.x or v3.x branches. Older versions are not guaranteed to work.
## Usage
### `clsBluebird( ns [, Promise] )`
```js
var cls = require('continuation-local-storage');
var ns = cls.createNamespace('myNamespace');
var Promise = require('bluebird');
var clsBluebird = require('cls-bluebird');
clsBluebird( ns );
// Promise is now patched to maintain CLS context
```
The above patches the "global" instance of bluebird. So anywhere else in the same app that calls `require('bluebird')` will get the patched version (assuming npm resolves to the same file).
### Patching a particular instance of Bluebird
So as not to alter the "global" instance of bluebird, it's recommended to first create a independent instance of the Bluebird constructor before patching, and pass it to cls-bluebird.
This is a more robust approach.
```js
var Promise = require('bluebird').getNewLibraryCopy();
var clsBluebird = require('cls-bluebird');
clsBluebird( ns, Promise );
```
(see [Promise.getNewLibraryCopy()](http://bluebirdjs.com/docs/api/promise.getnewlibrarycopy.html) docs on Bluebird website)
### Nature of patching
Combining CLS and promises is a slightly tricky business. There are 3 different conventions one could use (see [this issue](https://github.com/othiym23/node-continuation-local-storage/issues/64) for more detail).
`cls-bluebird` follows the convention of binding `.then()` callbacks **to the context in which `.then()` is called**.
```js
var promise;
ns.run(function() {
ns.set('foo', 123);
promise = Promise.resolve();
});
ns.run(function() {
ns.set('foo', 456);
promise.then(print);
});
function print() {
console.log(ns.get('foo'));
}
// this outputs '456' (the value of `foo` at the time `.then()` was called)
```
### Notes
#### Coroutines
The patch ensures that when execution in a coroutine continues after a `yield` statement, it always does so in the CLS context *in which the coroutine started running*.
```js
var fn = Promise.coroutine(function* () {
console.log('Context 1:', ns.get('foo'));
yield Promise.resolve();
console.log('Context 2:', ns.get('foo'));
});
ns.run(function(ctx) {
ns.set('foo', 123);
fn();
});
```
outputs:
```
Context 1: 123
Context 2: 123
```
This means:
1. If the `yield`-ed expression loses CLS context, the original CLS context will be restored after the `yield`.
2. Any code before the `yield` which changes CLS context will only be effective until the next `yield`.
#### Global error handlers
`Promise.onPossiblyUnhandledRejection()` and `Promise.onUnhandledRejectionHandled()` allow you to attach global handlers to intercept unhandled rejections.
The CLS context in which callbacks are called is unknown. It's probably unwise to rely on the CLS context in the callback being that when the rejection occurred - use `.catch()` on the end of the promise chain that's created within `namespace.run()` instead.
#### Progression
Bluebird v2.x contains a deprecated API for handling progression (`.progressed()`) etc. These methods are patched and *should* work fine but they're not covered by the tests.
## Tests
The tests cover every possible combination of input promises and callbacks that the Bluebird API allows. There's around 100,000 tests in total and the aim is to ensure cls-bluebird is as robust and reliable as possible.
Use `npm test` to run the tests. Use `npm run cover` to check coverage.
For more info on test tests, see [tests/README.md](https://github.com/TimBeyer/cls-bluebird/blob/master/test/README.md)
## Changelog
See [changelog.md](https://github.com/TimBeyer/cls-bluebird/blob/master/changelog.md)
## Issues/bugs
If you discover a bug, please raise an issue on Github. https://github.com/TimBeyer/cls-bluebird/issues
We are very keen to ensure cls-bluebird is completely bug-free and any bugs discovered will be fixed as soon as possible.
## Contribution
Pull requests are very welcome. Please:
* ensure all tests pass before submitting PR
* add an entry to changelog
* add tests for new features
* document new functionality/API additions in README
+48
View File
@@ -0,0 +1,48 @@
# Changelog
## 2.1.0
* Fix: `Promise.coroutine.addYieldHandler()` is maintained
* Patch `.tapCatch()` prototype method
* Tests: Workaround for uncaught rejections bug in Bluebird v3.5.1
* Travis CI run tests on Node versions 8 + 9
* Travis CI does not run tests on Node versions before v4
* Skip Travis CI runs on release tags
* Test against latest Bluebird v3
* Update dev dependencies
* Code style: Fix spacing in tests
## 2.0.1
* Correct typos in README
## 2.0.0
* Complete re-write
* New test suite
## 1.1.3
* Improved validation that `ns` argument is a namespace
* Add npm keywords
## 1.1.2
* README
## 1.1.1
* Use `is-bluebird` module for checking `Promise` argument
## 1.1.0
* Remove peer dependencies
* Update `shimmer` dependency
## 1.0.1
* Fix: `domain` argument for `_addCallbacks`
## 1.0.0
* Initial release
+265
View File
@@ -0,0 +1,265 @@
'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; }));
}
};
+50
View File
@@ -0,0 +1,50 @@
'use strict';
/*
* cls-bluebird
* Function to shim `Promise.prototype.call`
*/
// Modules
var shimmer = require('shimmer');
// Exports
var hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* Patch `call` method to run callbacks in current CLS context.
*
* @param {Function} Promise - Bluebird Promise constructor to patch
* @param {Object} ns - CLS namespace to bind callbacks to
* @returns {undefined}
*/
module.exports = function(Promise, ns) {
// Patch method
shimmer.wrap(Promise.prototype, 'call', function(callOriginal) {
return function() {
// Temporarily wrap `this._then` to bind the object method to current CLS context
// (`this.call()` will call `this._then()` synchronously)
var _thenOriginal = this._then,
ownProperty = hasOwnProperty.call(this, '_then');
this._then = function() {
// Unwrap `this._then`
if (ownProperty) {
this._then = _thenOriginal;
} else {
delete this._then;
}
// Bind function that will be called to call object method to CLS context
arguments[0] = ns.bind(arguments[0]);
// Run original `this._then` method
return _thenOriginal.apply(this, arguments);
};
// Call original `call` method
return callOriginal.apply(this, arguments);
};
});
};
+85
View File
@@ -0,0 +1,85 @@
'use strict';
/*
* cls-bluebird
* Function to shim `Promise.coroutine`
*
* Works by binding the `.next()` and `.throw()` methods of generator to CLS context
* at time when coroutine is executed.
*
* In bluebird v3.x, running the coroutine internally calls `.lastly()` if cancellation is enabled.
* To prevent unnecessary binding of the `.lastly()` callback to CLS context, this patch
* temporarily disables the patch on `Promise.prototype.lastly`.
* NB This patch could break if bluebird internals change, but this is covered by the tests.
*/
// Modules
var shimmer = require('shimmer');
// Exports
/**
* Patch `Promise.coroutine` or `Promise.spawn` to maintain current CLS context after all `yield` statements.
*
* @param {string} methodName - method name (either 'coroutine' or 'spawn')
* @param {Function} Promise - Bluebird Promise constructor to patch
* @param {Object} ns - CLS namespace to bind callbacks to
* @returns {undefined}
*/
module.exports = function(methodName, Promise, ns, v3) {
var lastlyPatched = Promise.prototype.lastly,
lastlyOriginal = Promise.prototype.lastly.__original;
// Patch method
shimmer.wrap(Promise, methodName, function(original) {
return function(generatorFunction, options) {
// NB If `generatorFunction` is not a function, do not alter it.
// Pass value directly to bluebird which will throw an error.
if (typeof generatorFunction === 'function') {
// Create proxy generator function
var generatorFunctionOriginal = generatorFunction;
generatorFunction = function() {
// Create generator from generator function
var generator = generatorFunctionOriginal.apply(this, arguments);
// Bind `.next()`, '.throw()' and `.return()` to current CLS context.
// NB CLS context is from when coroutine is called, not when created.
['next', 'throw', 'return'].forEach(function(name) {
if (typeof generator[name] === 'function') generator[name] = ns.bind(generator[name]);
});
return generator;
};
}
// Temporarily remove patch from `Promise.prototype.lastly` in bluebird v3
// to avoid unnecessary binding to CLS context.
var self = this;
if (methodName === 'spawn' && v3) {
return tempPatchLastly(function() {
return original.call(self, generatorFunction, options);
});
}
var fn = original.call(this, generatorFunction, options);
if (methodName === 'coroutine' && v3) {
return function() {
var self = this, args = arguments;
return tempPatchLastly(function() {
return fn.apply(self, args);
});
};
}
return fn;
};
});
function tempPatchLastly(fn) {
Promise.prototype.lastly = lastlyOriginal;
var res = fn();
Promise.prototype.lastly = lastlyPatched;
return res;
}
};
+41
View File
@@ -0,0 +1,41 @@
'use strict';
/*
* cls-bluebird
* Function to shim an object method to retain CLS context
*/
// Modules
var shimmer = require('shimmer');
// Exports
/**
* Patch method to run callbacks in current CLS context.
*
* @param {Object} obj - Object on which to find method
* @param {string} methodName - method name
* @param {Array} args - Array of indexes of arguments which are callbacks
* (negative numbers count from end e.g. -1 is last argument, -2 is penultimate)
* @param {Object} ns - CLS namespace to bind callbacks to
* @returns {undefined}
*/
module.exports = function(obj, methodName, args, ns) {
// Skip non-existent methods
if (!obj[methodName]) return;
// Patch method
shimmer.wrap(obj, methodName, function(original) {
return function() {
for (var i = 0; i < args.length; i++) {
var argIndex = args[i];
if (argIndex < 0) argIndex += arguments.length;
var callback = arguments[argIndex];
if (typeof callback === 'function') arguments[argIndex] = ns.bind(callback);
}
return original.apply(this, arguments);
};
});
};
+44
View File
@@ -0,0 +1,44 @@
'use strict';
/*
* cls-bluebird
* Function to shim `Promise.prototype._resolveFromExecutor`
* in order to patch `onCancel` handler in `new Promise()`.
*/
// Modules
var shimmer = require('shimmer');
// Exports
/**
* Patch `_resolveFromExecutor` proto method to run `onCancel` callbacks in current CLS context.
*
* @param {Function} Promise - Bluebird Promise constructor to patch
* @param {Object} ns - CLS namespace to bind callbacks to
* @returns {undefined}
*/
module.exports = function(Promise, ns) {
// Patch method
shimmer.wrap(Promise.prototype, '_resolveFromExecutor', function(_resolveFromExecutorOriginal) {
return function(executor) {
// Patch executor
var executorPatched = function() {
var onCancel = arguments[2];
if (onCancel) {
// Patch onCancel function
arguments[2] = function(fn) {
// Bind onCancel handler to current CLS context
if (typeof fn === 'function') fn = ns.bind(fn);
return onCancel.call(this, fn);
};
}
return executor.apply(this, arguments);
};
// Call original method
return _resolveFromExecutorOriginal.call(this, executorPatched);
};
});
};
+114
View File
@@ -0,0 +1,114 @@
'use strict';
/*
* cls-bluebird
* Function to shim `Promise.using`
*
* `Promise.using()` calls `.then()` and `.lastly` internally which leads to
* unnecessary CLS context binding with a naive patch.
*
* This custom patch intercepts calls to `Promise.all()` (v3) or `Promise.settle()` (v2)
* within `Promise.using()` and patches the resulting promise's `.then`/`.lastly` methods
* so they do not bind callbacks to CLS context.
*
* NB This patch could break if bluebird internals change, but this is covered by the tests.
*/
// Modules
var shimmer = require('shimmer');
// Exports
/**
* Patch `Promise.using` method to run callbacks in current CLS context.
*
* @param {Function} Promise - Bluebird Promise constructor to patch
* @param {Object} ns - CLS namespace to bind callbacks to
* @param {boolean} v3 - `true` if bluebird being patched is v3.x
* @returns {undefined}
*/
module.exports = function(Promise, ns, v3) {
(v3 ? patchV3 : patchV2)(Promise, ns);
};
// Patch for `Promise.using()` in bluebird v3
function patchV3(Promise, ns) {
var thenOriginal = Promise.prototype.then.__original,
lastlyOriginal = Promise.prototype.lastly.__original;
// Patch method
shimmer.wrap(Promise, 'using', function(usingOriginal) {
return function() {
// Bind `using` callback (last arg)
var argIndex = arguments.length - 1,
callback = arguments[argIndex];
if (typeof callback === 'function') arguments[argIndex] = ns.bind(callback);
// Temporarily patch `Promise.all()`
shimmer.wrap(Promise, 'all', function(allOriginal) {
return function(promises) {
// Remove temporary patch on `Promise.all()`
Promise.all = allOriginal;
// Call original `Promise.all()`
var p = allOriginal.call(this, promises);
// Patch `.then()` method on this promise to not bind callbacks
p.then = function() {
var p = thenOriginal.apply(this, arguments);
// Patch `.lastly()` method on this promise to not bind callbacks
p.lastly = lastlyOriginal;
return p;
};
return p;
};
});
// Call original `Promise.using()` method
return usingOriginal.apply(this, arguments);
};
});
}
// Patch for `Promise.using()` in bluebird v2
function patchV2(Promise, ns) {
var thenOriginal = Promise.prototype.then.__original;
// Patch method
shimmer.wrap(Promise, 'using', function(usingOriginal) {
return function() {
// Bind `using` callback (last arg)
var argIndex = arguments.length - 1,
callback = arguments[argIndex];
if (typeof callback === 'function') arguments[argIndex] = ns.bind(callback);
// Temporarily patch `Promise.settle()`
shimmer.wrap(Promise, 'settle', function(settleOriginal) {
return function(resources) {
// Remove temporary patch on `Promise.settle()`
Promise.settle = settleOriginal;
// Call original `Promise.settle()`
var p = settleOriginal.call(this, resources);
// Patch `.then()` method on this promise to not bind callbacks
p.then = function() {
var p = thenOriginal.apply(this, arguments);
// Patch `.then()` method on this promise to not bind callbacks
p.then = thenOriginal;
return p;
};
return p;
};
});
// Call original `Promise.using()` method
return usingOriginal.apply(this, arguments);
};
});
}
+90
View File
@@ -0,0 +1,90 @@
{
"_args": [
[
"cls-bluebird@2.1.0",
"/home/app"
]
],
"_from": "cls-bluebird@2.1.0",
"_id": "cls-bluebird@2.1.0",
"_inBundle": false,
"_integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=",
"_location": "/cls-bluebird",
"_phantomChildren": {},
"_requested": {
"type": "version",
"registry": true,
"raw": "cls-bluebird@2.1.0",
"name": "cls-bluebird",
"escapedName": "cls-bluebird",
"rawSpec": "2.1.0",
"saveSpec": null,
"fetchSpec": "2.1.0"
},
"_requiredBy": [
"/sequelize"
],
"_resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz",
"_spec": "2.1.0",
"_where": "/home/app",
"author": {
"name": "Tim Beyer",
"email": "tim.beyer@gmail.com"
},
"bugs": {
"url": "https://github.com/TimBeyer/cls-bluebird/issues"
},
"dependencies": {
"is-bluebird": "^1.0.2",
"shimmer": "^1.1.0"
},
"description": "Make bluebird work with the continuation-local-storage module.",
"devDependencies": {
"bluebird": "^2.10.2",
"bluebird2": "^3.0.0",
"bluebird3": "^3.1.1",
"chai": "^4.1.2",
"continuation-local-storage": "^3.2.1",
"coveralls": "^3.0.0",
"istanbul": "^0.4.5",
"jshint": "^2.9.5",
"lodash": "^4.17.4",
"mocha": "^4.0.1"
},
"homepage": "https://github.com/TimBeyer/cls-bluebird#readme",
"keywords": [
"continuation-local-storage",
"cls",
"bluebird",
"continuation",
"local",
"storage",
"promise",
"promises",
"async",
"thread",
"glue",
"baling-wire",
"patch"
],
"license": "BSD-2-Clause",
"main": "lib/index.js",
"name": "cls-bluebird",
"repository": {
"type": "git",
"url": "git+https://github.com/TimBeyer/cls-bluebird.git"
},
"scripts": {
"cover": "npm run cover-main && rm -rf coverage",
"cover-main": "COVERAGE=true BLUEBIRD_VERSION=3 istanbul cover _mocha --report lcovonly -- -R spec 'test/**/*.test.js'",
"coveralls": "npm run cover-main && cat ./coverage/lcov.info | coveralls && rm -rf ./coverage",
"jshint": "jshint lib test",
"test": "npm run jshint && npm run test-all",
"test-all": "npm run test-bluebird2 && npm run test-bluebird3",
"test-bluebird2": "BLUEBIRD_VERSION=2 npm run test-main",
"test-bluebird3": "BLUEBIRD_VERSION=3 npm run test-main",
"test-main": "mocha 'test/**/*.test.js'",
"travis": "bin/travis.sh"
},
"version": "2.1.0"
}