Skip to content

Commit 0435d61

Browse files
committed
Merge pull request #14 from jon-hall/feature/unwrapped-function-cache-bug
Fix issue with async functions being cached as-is, and so not getting…
2 parents 54659f9 + fe2b27c commit 0435d61

File tree

2 files changed

+56
-5
lines changed

2 files changed

+56
-5
lines changed

index.js

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,22 @@ function processExports(exports, test, cached, parentKeyName) {
1818
// Return early if this object has already been processed.
1919
if (cached.indexOf(exports) > -1) {
2020
return exports;
21+
} else if(typeof exports === "function") {
22+
// For functions, cache the original and wrapped version, else non-wrapped
23+
// functions end up being given back when encountered multiple times.
24+
var cacheResult = cached.filter(function(c) {
25+
return c.original === exports;
26+
});
27+
28+
if(cacheResult.length) {
29+
return cacheResult[0].wrapped;
30+
}
2131
}
2232

23-
// Record this object in the cache.
24-
cached.push(exports);
33+
// Record this object in the cache, if it is not a function.
34+
if(typeof exports != "function") {
35+
cached.push(exports);
36+
}
2537

2638
// Pass through if not an object or function.
2739
if (typeof exports != "object" && typeof exports != "function") {
@@ -32,14 +44,21 @@ function processExports(exports, test, cached, parentKeyName) {
3244

3345
// If a function, simply return it wrapped.
3446
if (typeof exports === "function") {
47+
// Assign the new function in place.
48+
var wrapped = Promise.denodeify(exports);
49+
50+
// Push the wrapped function onto the cache before processing properties,
51+
// else a cyclical function property causes a stack overflow.
52+
cached.push({
53+
original: exports,
54+
wrapped: wrapped
55+
});
56+
3557
// Find properties added to functions.
3658
for (var keyName in exports) {
3759
exports[keyName] = processExports(exports[keyName], test, cached, name);
3860
}
3961

40-
// Assign the new function in place.
41-
var wrapped = Promise.denodeify(exports);
42-
4362
// Find methods on the prototype, if there are any.
4463
if (Object.keys(exports.prototype).length) {
4564
processExports(exports.prototype, test, cached, name);

test/index.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,5 +104,37 @@ describe("Promisify", function() {
104104

105105
return new Test().a();
106106
});
107+
108+
it("can deal with the same async function being present in an object more than once", function() {
109+
var a = {
110+
a: function(d, cb) {
111+
cb && cb(null, d);
112+
}
113+
};
114+
115+
a.b = a.a;
116+
117+
a = promisify(a);
118+
119+
assert(a.a(5) !== undefined, "function not wrapped");
120+
assert(typeof a.a(5).then === "function", "function not wrapped");
121+
assert(a.b(5) !== undefined, "duplicate function not wrapped");
122+
assert(typeof a.b(5).then === "function", "duplicate function not wrapped");
123+
});
124+
125+
it("can deal with cyclical function properties", function() {
126+
var a = function(d, cb) {
127+
cb && cb(null, d);
128+
};
129+
130+
a.a = a;
131+
132+
a = promisify(a);
133+
134+
assert(a(5) !== undefined, "function not wrapped");
135+
assert(typeof a(5).then === "function", "function not wrapped");
136+
assert(a.a(5) !== undefined, "function property not wrapped");
137+
assert(typeof a.a(5).then === "function", "function property not wrapped");
138+
});
107139
});
108140
});

0 commit comments

Comments
 (0)