From be05c35168a93633b9b60ff32811545ced7bad49 Mon Sep 17 00:00:00 2001 From: 13xforever Date: Sat, 11 Jul 2015 20:51:30 +0500 Subject: [PATCH 1/2] Missing options parameters for .map(), .filter(), .promisifyAll(), and .nodeify() --- bluebird/bluebird-tests.ts | 232 +++++++++++++++++++++++++++++++++++-- bluebird/bluebird.d.ts | 57 +++++---- 2 files changed, 260 insertions(+), 29 deletions(-) diff --git a/bluebird/bluebird-tests.ts b/bluebird/bluebird-tests.ts index 7770e7c9b8..55ddf76973 100644 --- a/bluebird/bluebird-tests.ts +++ b/bluebird/bluebird-tests.ts @@ -1,4 +1,4 @@ -/// +/// // Tests by: Bart van der Schoor @@ -365,12 +365,12 @@ fooProm = fooProm.timeout(num, str); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - fooProm.nodeify(); -fooProm = fooProm.nodeify((err: any) => { +fooProm = fooProm.nodeify((err: any) => { }); +fooProm = fooProm.nodeify((err: any, foo?: Foo) => { }); -}); -fooProm = fooProm.nodeify((err: any, foo?: Foo) => { - -}); +fooProm.nodeify({ spread: true }); +fooProm = fooProm.nodeify((err: any) => { }, { spread: true }); +fooProm = fooProm.nodeify((err: any, foo?: Foo) => { }, { spread: true }); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -504,6 +504,17 @@ barArrProm = fooProm.map((item: Foo) => { return bar; }); +barArrProm = fooProm.map((item: Foo, index: number, arrayLength: number) => { + return bar; +}, { + concurrency: 1 +}); +barArrProm = fooProm.map((item: Foo) => { + return bar; +}, { + concurrency: 1 +}); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - barProm = fooProm.reduce((memo: Bar, item: Foo, index: number, arrayLength: number) => { @@ -522,6 +533,17 @@ fooArrProm = fooArrProm.filter((item: Foo) => { return bool; }); +fooArrProm = fooArrProm.filter((item: Foo, index: number, arrayLength: number) => { + return bool; +}, { + concurrency: 1 +}); +fooArrProm = fooArrProm.filter((item: Foo) => { + return bool; +}, { + concurrency: 1 +}); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -613,12 +635,41 @@ voidProm = Promise.delay(num); func = Promise.promisify(f); func = Promise.promisify(f, obj); -; obj = Promise.promisifyAll(obj); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +declare var util: any; + +function defaultFilter(name, func) { + return util.isIdentifier(name) && + name.charAt(0) !== "_" && + !util.isClass(func); +} + +function DOMPromisifier(originalMethod) { + // return a function + return function promisified() { + var args = [].slice.call(arguments); + // Needed so that the original method can be called with the correct receiver + var self = this; + // which returns a promise + return new Promise(function(resolve, reject) { + args.push(resolve, reject); + originalMethod.apply(self, args); + }); + }; +} + +obj = Promise.promisifyAll(obj, { + suffix: "", + filter: defaultFilter, + promisifier: DOMPromisifier +}); + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //TODO enable generator /* func = Promise.coroutine(f); @@ -704,6 +755,26 @@ barArrProm = Promise.map(fooThenArrThen, (item: Foo, index: number, arrayLength: return barThen; }); +barArrProm = Promise.map(fooThenArrThen, (item: Foo) => { + return bar; +}, { + concurrency: 1 +}); +barArrProm = Promise.map(fooThenArrThen, (item: Foo) => { + return barThen; +}, { + concurrency: 1 +}); +barArrProm = Promise.map(fooThenArrThen, (item: Foo, index: number, arrayLength: number) => { + return bar; +}, { + concurrency: 1 +}); +barArrProm = Promise.map(fooThenArrThen, (item: Foo, index: number, arrayLength: number) => { + return barThen; +}, { + concurrency: 1 +}); // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // fooArrThen @@ -721,6 +792,27 @@ barArrProm = Promise.map(fooArrThen, (item: Foo, index: number, arrayLength: num return barThen; }); +barArrProm = Promise.map(fooArrThen, (item: Foo) => { + return bar; +}, { + concurrency: 1 +}); +barArrProm = Promise.map(fooArrThen, (item: Foo) => { + return barThen; +}, { + concurrency: 1 +}); +barArrProm = Promise.map(fooArrThen, (item: Foo, index: number, arrayLength: number) => { + return bar; +}, { + concurrency: 1 +}); +barArrProm = Promise.map(fooArrThen, (item: Foo, index: number, arrayLength: number) => { + return barThen; +}, { + concurrency: 1 +}); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // fooThenArr @@ -738,6 +830,27 @@ barArrProm = Promise.map(fooThenArr, (item: Foo, index: number, arrayLength: num return barThen; }); +barArrProm = Promise.map(fooThenArr, (item: Foo) => { + return bar; +}, { + concurrency: 1 +}); +barArrProm = Promise.map(fooThenArr, (item: Foo) => { + return barThen; +}, { + concurrency: 1 +}); +barArrProm = Promise.map(fooThenArr, (item: Foo, index: number, arrayLength: number) => { + return bar; +}, { + concurrency: 1 +}); +barArrProm = Promise.map(fooThenArr, (item: Foo, index: number, arrayLength: number) => { + return barThen; +}, { + concurrency: 1 +}); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // fooArr @@ -755,6 +868,27 @@ barArrProm = Promise.map(fooArr, (item: Foo, index: number, arrayLength: number) return barThen; }); +barArrProm = Promise.map(fooArr, (item: Foo) => { + return bar; +}, { + concurrency: 1 +}); +barArrProm = Promise.map(fooArr, (item: Foo) => { + return barThen; +}, { + concurrency: 1 +}); +barArrProm = Promise.map(fooArr, (item: Foo, index: number, arrayLength: number) => { + return bar; +}, { + concurrency: 1 +}); +barArrProm = Promise.map(fooArr, (item: Foo, index: number, arrayLength: number) => { + return barThen; +}, { + concurrency: 1 +}); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // reduce() @@ -848,6 +982,27 @@ fooArrProm = Promise.filter(fooThenArrThen, (item: Foo, index: number, arrayLeng return boolThen; }); +fooArrProm = Promise.filter(fooThenArrThen, (item: Foo) => { + return bool; +}, { + concurrency: 1 +}); +fooArrProm = Promise.filter(fooThenArrThen, (item: Foo) => { + return boolThen; +}, { + concurrency: 1 +}); +fooArrProm = Promise.filter(fooThenArrThen, (item: Foo, index: number, arrayLength: number) => { + return bool; +}, { + concurrency: 1 +}); +fooArrProm = Promise.filter(fooThenArrThen, (item: Foo, index: number, arrayLength: number) => { + return boolThen; +}, { + concurrency: 1 +}); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // fooArrThen @@ -865,6 +1020,27 @@ fooArrProm = Promise.filter(fooArrThen, (item: Foo, index: number, arrayLength: return boolThen; }); +fooArrProm = Promise.filter(fooArrThen, (item: Foo) => { + return bool; +}, { + concurrency: 1 +}); +fooArrProm = Promise.filter(fooArrThen, (item: Foo) => { + return boolThen; +}, { + concurrency: 1 +}); +fooArrProm = Promise.filter(fooArrThen, (item: Foo, index: number, arrayLength: number) => { + return bool; +}, { + concurrency: 1 +}); +fooArrProm = Promise.filter(fooArrThen, (item: Foo, index: number, arrayLength: number) => { + return boolThen; +}, { + concurrency: 1 +}); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // fooThenArr @@ -882,6 +1058,27 @@ fooArrProm = Promise.filter(fooThenArr, (item: Foo, index: number, arrayLength: return boolThen; }); +fooArrProm = Promise.filter(fooThenArr, (item: Foo) => { + return bool; +}, { + concurrency: 1 +}); +fooArrProm = Promise.filter(fooThenArr, (item: Foo) => { + return boolThen; +}, { + concurrency: 1 +}); +fooArrProm = Promise.filter(fooThenArr, (item: Foo, index: number, arrayLength: number) => { + return bool; +}, { + concurrency: 1 +}); +fooArrProm = Promise.filter(fooThenArr, (item: Foo, index: number, arrayLength: number) => { + return boolThen; +}, { + concurrency: 1 +}); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // fooArr @@ -899,4 +1096,25 @@ fooArrProm = Promise.filter(fooArr, (item: Foo, index: number, arrayLength: numb return boolThen; }); +fooArrProm = Promise.filter(fooArr, (item: Foo) => { + return bool; +}, { + concurrency: 1 +}); +fooArrProm = Promise.filter(fooArr, (item: Foo) => { + return boolThen; +}, { + concurrency: 1 +}); +fooArrProm = Promise.filter(fooArr, (item: Foo, index: number, arrayLength: number) => { + return bool; +}, { + concurrency: 1 +}); +fooArrProm = Promise.filter(fooArr, (item: Foo, index: number, arrayLength: number) => { + return boolThen; +}, { + concurrency: 1 +}); + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/bluebird/bluebird.d.ts b/bluebird/bluebird.d.ts index cd21d77e92..a0ccd30ec5 100644 --- a/bluebird/bluebird.d.ts +++ b/bluebird/bluebird.d.ts @@ -116,7 +116,7 @@ declare class Promise implements Promise.Thenable, Promise.Inspection { * Register a node-style callback on this promise. When this promise is is either fulfilled or rejected, the node callback will be called back with the node.js convention where error reason is the first argument and success value is the second argument. The error argument will be `null` in case of success. * Returns back this promise instead of creating a new one. If the `callback` argument is not a function, this method does not do anything. */ - nodeify(callback: (err: any, value?: R) => void): Promise; + nodeify(callback: (err: any, value?: R) => void, options?: Promise.SpreadOption): Promise; nodeify(...sink: any[]): void; /** @@ -312,8 +312,8 @@ declare class Promise implements Promise.Thenable, Promise.Inspection { * Same as calling `Promise.map(thisPromise, mapper)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ // TODO type inference from array-resolving promise? - map(mapper: (item: Q, index: number, arrayLength: number) => Promise.Thenable): Promise; - map(mapper: (item: Q, index: number, arrayLength: number) => U): Promise; + map(mapper: (item: Q, index: number, arrayLength: number) => Promise.Thenable, options?: Promise.ConcurrencyOption): Promise; + map(mapper: (item: Q, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; /** * Same as calling `Promise.reduce(thisPromise, Function reducer, initialValue)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. @@ -326,8 +326,8 @@ declare class Promise implements Promise.Thenable, Promise.Inspection { * Same as calling ``Promise.filter(thisPromise, filterer)``. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ // TODO type inference from array-resolving promise? - filter(filterer: (item: U, index: number, arrayLength: number) => Promise.Thenable): Promise; - filter(filterer: (item: U, index: number, arrayLength: number) => boolean): Promise; + filter(filterer: (item: U, index: number, arrayLength: number) => Promise.Thenable, options?: Promise.ConcurrencyOption): Promise; + filter(filterer: (item: U, index: number, arrayLength: number) => boolean, options?: Promise.ConcurrencyOption): Promise; /** * Start the chain of promises with `Promise.try`. Any synchronous exceptions will be turned into rejections on the returned promise. @@ -416,7 +416,7 @@ declare class Promise implements Promise.Thenable, Promise.Inspection { * Note that the original methods on the object are not overwritten but new methods are created with the `Async`-postfix. For example, if you `promisifyAll()` the node.js `fs` object use `fs.statAsync()` to call the promisified `stat` method. */ // TODO how to model promisifyAll? - static promisifyAll(target: Object): Object; + static promisifyAll(target: Object, options?: Promise.PromisifyAllOptions): Object; /** * Returns a function that can use `yield` to run asynchronous code synchronously. This feature requires the support of generators which are drafted in the next version of the language. Node version greater than `0.11.2` is required and needs to be executed with the `--harmony-generators` (or `--harmony`) command-line switch. @@ -542,20 +542,20 @@ declare class Promise implements Promise.Thenable, Promise.Inspection { * *The original array is not modified.* */ // promise of array with promises of value - static map(values: Promise.Thenable[]>, mapper: (item: R, index: number, arrayLength: number) => Promise.Thenable): Promise; - static map(values: Promise.Thenable[]>, mapper: (item: R, index: number, arrayLength: number) => U): Promise; + static map(values: Promise.Thenable[]>, mapper: (item: R, index: number, arrayLength: number) => Promise.Thenable, options?: Promise.ConcurrencyOption): Promise; + static map(values: Promise.Thenable[]>, mapper: (item: R, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; // promise of array with values - static map(values: Promise.Thenable, mapper: (item: R, index: number, arrayLength: number) => Promise.Thenable): Promise; - static map(values: Promise.Thenable, mapper: (item: R, index: number, arrayLength: number) => U): Promise; + static map(values: Promise.Thenable, mapper: (item: R, index: number, arrayLength: number) => Promise.Thenable, options?: Promise.ConcurrencyOption): Promise; + static map(values: Promise.Thenable, mapper: (item: R, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; // array with promises of value - static map(values: Promise.Thenable[], mapper: (item: R, index: number, arrayLength: number) => Promise.Thenable): Promise; - static map(values: Promise.Thenable[], mapper: (item: R, index: number, arrayLength: number) => U): Promise; + static map(values: Promise.Thenable[], mapper: (item: R, index: number, arrayLength: number) => Promise.Thenable, options?: Promise.ConcurrencyOption): Promise; + static map(values: Promise.Thenable[], mapper: (item: R, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; // array with values - static map(values: R[], mapper: (item: R, index: number, arrayLength: number) => Promise.Thenable): Promise; - static map(values: R[], mapper: (item: R, index: number, arrayLength: number) => U): Promise; + static map(values: R[], mapper: (item: R, index: number, arrayLength: number) => Promise.Thenable, options?: Promise.ConcurrencyOption): Promise; + static map(values: R[], mapper: (item: R, index: number, arrayLength: number) => U, options?: Promise.ConcurrencyOption): Promise; /** * Reduce an array, or a promise of an array, which contains a promises (or a mix of promises and values) with the given `reducer` function with the signature `(total, current, index, arrayLength)` where `item` is the resolved value of a respective promise in the input array. If any promise in the input array is rejected the returned promise is rejected as well. @@ -588,20 +588,20 @@ declare class Promise implements Promise.Thenable, Promise.Inspection { * *The original array is not modified. */ // promise of array with promises of value - static filter(values: Promise.Thenable[]>, filterer: (item: R, index: number, arrayLength: number) => Promise.Thenable): Promise; - static filter(values: Promise.Thenable[]>, filterer: (item: R, index: number, arrayLength: number) => boolean): Promise; + static filter(values: Promise.Thenable[]>, filterer: (item: R, index: number, arrayLength: number) => Promise.Thenable, option?: Promise.ConcurrencyOption): Promise; + static filter(values: Promise.Thenable[]>, filterer: (item: R, index: number, arrayLength: number) => boolean, option?: Promise.ConcurrencyOption): Promise; // promise of array with values - static filter(values: Promise.Thenable, filterer: (item: R, index: number, arrayLength: number) => Promise.Thenable): Promise; - static filter(values: Promise.Thenable, filterer: (item: R, index: number, arrayLength: number) => boolean): Promise; + static filter(values: Promise.Thenable, filterer: (item: R, index: number, arrayLength: number) => Promise.Thenable, option?: Promise.ConcurrencyOption): Promise; + static filter(values: Promise.Thenable, filterer: (item: R, index: number, arrayLength: number) => boolean, option?: Promise.ConcurrencyOption): Promise; // array with promises of value - static filter(values: Promise.Thenable[], filterer: (item: R, index: number, arrayLength: number) => Promise.Thenable): Promise; - static filter(values: Promise.Thenable[], filterer: (item: R, index: number, arrayLength: number) => boolean): Promise; + static filter(values: Promise.Thenable[], filterer: (item: R, index: number, arrayLength: number) => Promise.Thenable, option?: Promise.ConcurrencyOption): Promise; + static filter(values: Promise.Thenable[], filterer: (item: R, index: number, arrayLength: number) => boolean, option?: Promise.ConcurrencyOption): Promise; // array with values - static filter(values: R[], filterer: (item: R, index: number, arrayLength: number) => Promise.Thenable): Promise; - static filter(values: R[], filterer: (item: R, index: number, arrayLength: number) => boolean): Promise; + static filter(values: R[], filterer: (item: R, index: number, arrayLength: number) => Promise.Thenable, option?: Promise.ConcurrencyOption): Promise; + static filter(values: R[], filterer: (item: R, index: number, arrayLength: number) => boolean, option?: Promise.ConcurrencyOption): Promise; } declare module Promise { @@ -618,6 +618,19 @@ declare module Promise { export interface OperationalError extends Error { } + export interface ConcurrencyOption { + concurrency: number; + } + export interface SpreadOption { + spread: boolean; + } + export interface PromisifyAllOptions { + suffix?: string; + filter?: (name: string, func: Function, target?: any, passesDefaultFilter?: boolean) => boolean; + // The promisifier gets a reference to the original method and should return a function which returns a promise + promisifier?: (originalMethod: Function) => () => Thenable ; + } + // Ideally, we'd define e.g. "export class RangeError extends Error {}", // but as Error is defined as an interface (not a class), TypeScript doesn't // allow extending Error, only implementing it. From a98c5955e885bbef667c2a3aaf35fcc3e913f5c8 Mon Sep 17 00:00:00 2001 From: 13xforever Date: Sat, 11 Jul 2015 20:58:02 +0500 Subject: [PATCH 2/2] explicit typings in tests --- bluebird/bluebird-tests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bluebird/bluebird-tests.ts b/bluebird/bluebird-tests.ts index 55ddf76973..f338678c79 100644 --- a/bluebird/bluebird-tests.ts +++ b/bluebird/bluebird-tests.ts @@ -642,13 +642,13 @@ obj = Promise.promisifyAll(obj); declare var util: any; -function defaultFilter(name, func) { +function defaultFilter(name: string, func: Function) { return util.isIdentifier(name) && name.charAt(0) !== "_" && !util.isClass(func); } -function DOMPromisifier(originalMethod) { +function DOMPromisifier(originalMethod: Function) { // return a function return function promisified() { var args = [].slice.call(arguments);