From 0ab91eb4c1da914efbf03a2732629914cd3398dc Mon Sep 17 00:00:00 2001 From: Ben Lesh Date: Tue, 8 Feb 2022 10:06:25 -0600 Subject: [PATCH] fix(subscribe): allow interop with Monio and other libraries that patch function bind * fix(subscribe): allows functions where bind has been patched to be weird Apparently, code exists in the wild that will patch function bind to do something other than return a function that will execute the function instance, so we cannot rely on bind. Resolves #6783 * refactor: Alternative bind approach * chore: update side-effects golden files. * chore: Add comment about why bind is captured * chore: update side-effect files again --- .../side-effects/snapshots/esm/ajax.js | 2 +- .../side-effects/snapshots/esm/fetch.js | 2 ++ .../side-effects/snapshots/esm/index.js | 2 ++ .../side-effects/snapshots/esm/operators.js | 2 ++ .../side-effects/snapshots/esm/testing.js | 2 ++ .../side-effects/snapshots/esm/websocket.js | 2 +- .../side-effects/snapshots/esm5/ajax.js | 2 ++ .../side-effects/snapshots/esm5/fetch.js | 2 ++ .../side-effects/snapshots/esm5/index.js | 2 ++ .../side-effects/snapshots/esm5/operators.js | 2 ++ .../side-effects/snapshots/esm5/testing.js | 2 ++ .../side-effects/snapshots/esm5/websocket.js | 2 ++ spec/Observable-spec.ts | 28 +++++++++++++++++++ src/internal/Subscriber.ts | 17 +++++++++-- 14 files changed, 64 insertions(+), 5 deletions(-) diff --git a/integration/side-effects/snapshots/esm/ajax.js b/integration/side-effects/snapshots/esm/ajax.js index 8b13789179..f758d1ed1e 100644 --- a/integration/side-effects/snapshots/esm/ajax.js +++ b/integration/side-effects/snapshots/esm/ajax.js @@ -1 +1 @@ - +const _bind = Function.prototype.bind; diff --git a/integration/side-effects/snapshots/esm/fetch.js b/integration/side-effects/snapshots/esm/fetch.js index 5d63e0559f..0ba0272b17 100644 --- a/integration/side-effects/snapshots/esm/fetch.js +++ b/integration/side-effects/snapshots/esm/fetch.js @@ -1 +1,3 @@ import "tslib"; + +const _bind = Function.prototype.bind; diff --git a/integration/side-effects/snapshots/esm/index.js b/integration/side-effects/snapshots/esm/index.js index 70c2dab83c..e78af7914a 100644 --- a/integration/side-effects/snapshots/esm/index.js +++ b/integration/side-effects/snapshots/esm/index.js @@ -1,5 +1,7 @@ import "tslib"; +const _bind = Function.prototype.bind; + var NotificationKind; (function(NotificationKind) { diff --git a/integration/side-effects/snapshots/esm/operators.js b/integration/side-effects/snapshots/esm/operators.js index 70c2dab83c..e78af7914a 100644 --- a/integration/side-effects/snapshots/esm/operators.js +++ b/integration/side-effects/snapshots/esm/operators.js @@ -1,5 +1,7 @@ import "tslib"; +const _bind = Function.prototype.bind; + var NotificationKind; (function(NotificationKind) { diff --git a/integration/side-effects/snapshots/esm/testing.js b/integration/side-effects/snapshots/esm/testing.js index 70c2dab83c..e78af7914a 100644 --- a/integration/side-effects/snapshots/esm/testing.js +++ b/integration/side-effects/snapshots/esm/testing.js @@ -1,5 +1,7 @@ import "tslib"; +const _bind = Function.prototype.bind; + var NotificationKind; (function(NotificationKind) { diff --git a/integration/side-effects/snapshots/esm/websocket.js b/integration/side-effects/snapshots/esm/websocket.js index 8b13789179..f758d1ed1e 100644 --- a/integration/side-effects/snapshots/esm/websocket.js +++ b/integration/side-effects/snapshots/esm/websocket.js @@ -1 +1 @@ - +const _bind = Function.prototype.bind; diff --git a/integration/side-effects/snapshots/esm5/ajax.js b/integration/side-effects/snapshots/esm5/ajax.js index 5d63e0559f..65c08c7854 100644 --- a/integration/side-effects/snapshots/esm5/ajax.js +++ b/integration/side-effects/snapshots/esm5/ajax.js @@ -1 +1,3 @@ import "tslib"; + +var _bind = Function.prototype.bind; diff --git a/integration/side-effects/snapshots/esm5/fetch.js b/integration/side-effects/snapshots/esm5/fetch.js index 5d63e0559f..65c08c7854 100644 --- a/integration/side-effects/snapshots/esm5/fetch.js +++ b/integration/side-effects/snapshots/esm5/fetch.js @@ -1 +1,3 @@ import "tslib"; + +var _bind = Function.prototype.bind; diff --git a/integration/side-effects/snapshots/esm5/index.js b/integration/side-effects/snapshots/esm5/index.js index 70c2dab83c..98dea9ad72 100644 --- a/integration/side-effects/snapshots/esm5/index.js +++ b/integration/side-effects/snapshots/esm5/index.js @@ -1,5 +1,7 @@ import "tslib"; +var _bind = Function.prototype.bind; + var NotificationKind; (function(NotificationKind) { diff --git a/integration/side-effects/snapshots/esm5/operators.js b/integration/side-effects/snapshots/esm5/operators.js index 70c2dab83c..98dea9ad72 100644 --- a/integration/side-effects/snapshots/esm5/operators.js +++ b/integration/side-effects/snapshots/esm5/operators.js @@ -1,5 +1,7 @@ import "tslib"; +var _bind = Function.prototype.bind; + var NotificationKind; (function(NotificationKind) { diff --git a/integration/side-effects/snapshots/esm5/testing.js b/integration/side-effects/snapshots/esm5/testing.js index 70c2dab83c..98dea9ad72 100644 --- a/integration/side-effects/snapshots/esm5/testing.js +++ b/integration/side-effects/snapshots/esm5/testing.js @@ -1,5 +1,7 @@ import "tslib"; +var _bind = Function.prototype.bind; + var NotificationKind; (function(NotificationKind) { diff --git a/integration/side-effects/snapshots/esm5/websocket.js b/integration/side-effects/snapshots/esm5/websocket.js index 5d63e0559f..65c08c7854 100644 --- a/integration/side-effects/snapshots/esm5/websocket.js +++ b/integration/side-effects/snapshots/esm5/websocket.js @@ -1 +1,3 @@ import "tslib"; + +var _bind = Function.prototype.bind; diff --git a/spec/Observable-spec.ts b/spec/Observable-spec.ts index 630cd5085d..672a724c6b 100644 --- a/spec/Observable-spec.ts +++ b/spec/Observable-spec.ts @@ -191,6 +191,34 @@ describe('Observable', () => { }); describe('subscribe', () => { + it('should work with handlers with hacked bind methods', () => { + const source = of('Hi'); + const results: any[] = []; + const next = function (value: string) { + results.push(value); + } + next.bind = () => { /* lol */}; + + const complete = function () { + results.push('done'); + } + complete.bind = () => { /* lol */}; + + source.subscribe({ next, complete }); + expect(results).to.deep.equal(['Hi', 'done']); + }); + + it('should work with handlers with hacked bind methods, in the error case', () => { + const source = throwError(() => 'an error'); + const results: any[] = []; + const error = function (value: string) { + results.push(value); + } + + source.subscribe({ error }); + expect(results).to.deep.equal(['an error']); + }); + it('should be synchronous', () => { let subscribed = false; let nexted: string; diff --git a/src/internal/Subscriber.ts b/src/internal/Subscriber.ts index de010710d3..5862a8d91b 100644 --- a/src/internal/Subscriber.ts +++ b/src/internal/Subscriber.ts @@ -136,6 +136,17 @@ export class Subscriber extends Subscription implements Observer { } } +/** + * This bind is captured here because we want to be able to have + * compatibility with monoid libraries that tend to use a method named + * `bind`. In particular, a library called Monio requires this. + */ +const _bind = Function.prototype.bind; + +function bind any>(fn: Fn, thisArg: any): Fn { + return _bind.call(fn, thisArg); +} + export class SafeSubscriber extends Subscriber { constructor( observerOrNext?: Partial> | ((value: T) => void) | null, @@ -166,9 +177,9 @@ export class SafeSubscriber extends Subscriber { } else { context = observerOrNext; } - next = next?.bind(context); - error = error?.bind(context); - complete = complete?.bind(context); + next = next && bind(next, context); + error = error && bind(error, context); + complete = complete && bind(complete, context); } // Once we set the destination, the superclass `Subscriber` will