Skip to content

Commit

Permalink
fix(promisify): fix promisify to return aigle instances #59
Browse files Browse the repository at this point in the history
  • Loading branch information
suguru03 committed May 1, 2018
1 parent 3b917f8 commit ea3c5f0
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 42 deletions.
49 changes: 38 additions & 11 deletions lib/promisify.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const Aigle = require('./aigle');
const { INTERNAL } = require('./internal/util');
const { INTERNAL, callThen } = require('./internal/util');

const globalSetImmediate = typeof setImmediate === 'function' ? setImmediate : {};
const custom =
Expand Down Expand Up @@ -30,6 +30,9 @@ function promisify(fn, opts) {
switch (typeof opts) {
case 'string':
case 'number':
if (typeof fn[opts] !== 'function') {
throw new TypeError('Function not found key: ' + opts);
}
if (fn[opts].__isPromisified__) {
return fn[opts];
}
Expand All @@ -41,16 +44,6 @@ function promisify(fn, opts) {
if (fn.__isPromisified__) {
return fn;
}
const func = fn[custom];
if (func) {
return func;
}
switch (fn) {
case setTimeout:
return Aigle.delay;
case globalSetImmediate:
return Aigle.resolve;
}
const ctx = opts && opts.context !== undefined ? opts.context : undefined;
return makeFunction(fn, ctx);
default:
Expand Down Expand Up @@ -105,9 +98,43 @@ function makeFunctionByKey(obj, key) {
* @param {*} [ctx]
*/
function makeFunction(fn, ctx) {
const func = fn[custom];
if (func) {
nativePromisified.__isPromisified__ = true;
return nativePromisified;
}
switch (fn) {
case setTimeout:
return Aigle.delay;
case globalSetImmediate:
return Aigle.resolve;
}
promisified.__isPromisified__ = true;
return promisified;

function nativePromisified(arg) {
const promise = new Aigle(INTERNAL);
let l = arguments.length;
let p;
switch (l) {
case 0:
p = func.call(ctx || this);
break;
case 1:
p = func.call(ctx || this, arg);
break;
default:
const args = Array(l);
while (l--) {
args[l] = arguments[l];
}
p = func.apply(ctx || this, args);
break;
}
callThen(p, promise);
return promise;
}

function promisified(arg) {
const promise = new Aigle(INTERNAL);
const callback = makeCallback(promise);
Expand Down
7 changes: 1 addition & 6 deletions lib/promisifyAll.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,12 @@ function _promisifyAll(suffix, filter, obj, key, target, depth) {
return;
}
const _key = `${key}${suffix}`;
const promisified = promisify(obj);
if (target[_key]) {
// it is for native promisified functions
if (target[_key] === promisified) {
break;
}
if (!target[_key].__isPromisified__) {
throw new TypeError(`Cannot promisify an API that has normal methods with '${suffix}'-suffix`);
}
} else {
target[_key] = promisified;
target[_key] = promisify(obj);
}
}
iterate(suffix, filter, obj, obj, depth, memo);
Expand Down
69 changes: 44 additions & 25 deletions test/lib/test.promisify.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ const Aigle = require('../../');
const { DELAY } = require('../config');

parallel('promisify', () => {
const dirpath = path.resolve(__dirname, '../../lib');
const aiglepath = path.resolve(dirpath, 'aigle.js');
beforeEach(() => {
const re = new RegExp(dirpath);
delete require.cache[aiglepath];
_.forOwn(require.cache, (cache, filepath) => {
if (re.test(filepath)) {
delete require.cache[filepath];
}
});
});

it('should execute', () => {
const fn = callback => {
setTimeout(() => callback(null, 1), 10);
Expand Down Expand Up @@ -170,45 +182,52 @@ parallel('promisify', () => {
it('should work setTimeout the same functionality as util.promisify', () => {
const setTimeoutPromise = Aigle.promisify(setTimeout);
const str = 'foobar';
if (custom) {
assert.strictEqual(setTimeoutPromise, setTimeout[custom]);
}
return setTimeoutPromise(DELAY, str).then(value => assert.strictEqual(value, str));
assert.notStrictEqual(setTimeoutPromise, setTimeout[custom]);
const promise = setTimeoutPromise(DELAY, str).then(value => assert.strictEqual(value, str));
assert.ok(promise instanceof Aigle);
return promise;
});

it('should work setImmediate the same functionality as util.promisify', () => {
const setImmedidatePromise = Aigle.promisify(setImmediate);
const setImmediatePromise = Aigle.promisify(setImmediate);
const str = 'foobar';
if (custom) {
assert.strictEqual(setImmedidatePromise, setImmediate[custom]);
}
return setImmedidatePromise(str).then(value => assert.strictEqual(value, str));
assert.notStrictEqual(setImmediatePromise, setImmediate[custom]);
const promise = setImmediatePromise(str).then(value => assert.strictEqual(value, str));
assert.ok(promise instanceof Aigle);
return promise;
});

it('should get the native promisified exec', () => {
const promisified = Aigle.promisify(exec);
assert.ok(promisified);
if (custom) {
assert.strictEqual(promisified, exec[custom]);
}
assert.notStrictEqual(promisified, exec[custom]);
});

it('should return aigle promisified native function', () => {
const setImmediatePromise = Aigle.promisify(setImmediate);
return setImmediatePromise()
.then(() => setImmediatePromise([1, 2, 3]))
.map(v => v * 2)
.then(arr => assert.deepStrictEqual(arr, [2, 4, 6]));
});

it('should work even if util promisify does not exist', () => {
it('should work with setImmediate even if util promisify does not exist', () => {
util.promisify = null;
const dirpath = path.resolve(__dirname, '../../lib');
const aiglepath = path.resolve(dirpath, 'aigle.js');
const re = new RegExp(dirpath);
delete require.cache[aiglepath];
_.forOwn(require.cache, (cache, filepath) => {
if (re.test(filepath)) {
delete require.cache[filepath];
}
});
const Aigle = require(aiglepath);
const setImmediatePromise = Aigle.promisify(setImmediate);
assert.notStrictEqual(setImmediatePromise, setImmediate[custom]);
const str = 'foobar';
const promise = setImmediatePromise(str).then(value => assert.strictEqual(value, str));
assert.ok(promise instanceof Aigle);
return promise;
});

const setImmedidatePromise = Aigle.promisify(setImmediate);
assert.notStrictEqual(setImmedidatePromise, setImmediate[custom]);
it('should work with setImmediate even if util promisify does not exist', () => {
util.promisify = null;
const Aigle = require(aiglepath);
const setTimeoutPromise = Aigle.promisify(setTimeout);
assert.notStrictEqual(setTimeoutPromise, setTimeout[custom]);
const str = 'foobar';
return setImmedidatePromise(str).then(value => assert.strictEqual(value, str));
return setTimeoutPromise(DELAY, str).then(value => assert.strictEqual(value, str));
});
});

0 comments on commit ea3c5f0

Please sign in to comment.