Actualizacion maquina principal
[dotfiles/.git] / .config / coc / extensions / node_modules / coc-prettier / node_modules / rxjs / src / internal / Subscription.ts
1 import { isArray } from './util/isArray';
2 import { isObject } from './util/isObject';
3 import { isFunction } from './util/isFunction';
4 import { UnsubscriptionError } from './util/UnsubscriptionError';
5 import { SubscriptionLike, TeardownLogic } from './types';
6
7 /**
8  * Represents a disposable resource, such as the execution of an Observable. A
9  * Subscription has one important method, `unsubscribe`, that takes no argument
10  * and just disposes the resource held by the subscription.
11  *
12  * Additionally, subscriptions may be grouped together through the `add()`
13  * method, which will attach a child Subscription to the current Subscription.
14  * When a Subscription is unsubscribed, all its children (and its grandchildren)
15  * will be unsubscribed as well.
16  *
17  * @class Subscription
18  */
19 export class Subscription implements SubscriptionLike {
20   /** @nocollapse */
21   public static EMPTY: Subscription = (function(empty: any) {
22     empty.closed = true;
23     return empty;
24   }(new Subscription()));
25
26   /**
27    * A flag to indicate whether this Subscription has already been unsubscribed.
28    * @type {boolean}
29    */
30   public closed: boolean = false;
31
32   /** @internal */
33   protected _parentOrParents: Subscription | Subscription[] = null;
34   /** @internal */
35   private _subscriptions: SubscriptionLike[] = null;
36
37   /**
38    * @param {function(): void} [unsubscribe] A function describing how to
39    * perform the disposal of resources when the `unsubscribe` method is called.
40    */
41   constructor(unsubscribe?: () => void) {
42     if (unsubscribe) {
43       (<any> this)._unsubscribe = unsubscribe;
44     }
45   }
46
47   /**
48    * Disposes the resources held by the subscription. May, for instance, cancel
49    * an ongoing Observable execution or cancel any other type of work that
50    * started when the Subscription was created.
51    * @return {void}
52    */
53   unsubscribe(): void {
54     let errors: any[];
55
56     if (this.closed) {
57       return;
58     }
59
60     let { _parentOrParents, _unsubscribe, _subscriptions } = (<any> this);
61
62     this.closed = true;
63     this._parentOrParents = null;
64     // null out _subscriptions first so any child subscriptions that attempt
65     // to remove themselves from this subscription will noop
66     this._subscriptions = null;
67
68     if (_parentOrParents instanceof Subscription) {
69       _parentOrParents.remove(this);
70     } else if (_parentOrParents !== null) {
71       for (let index = 0; index < _parentOrParents.length; ++index) {
72         const parent = _parentOrParents[index];
73         parent.remove(this);
74       }
75     }
76
77     if (isFunction(_unsubscribe)) {
78       try {
79         _unsubscribe.call(this);
80       } catch (e) {
81         errors = e instanceof UnsubscriptionError ? flattenUnsubscriptionErrors(e.errors) : [e];
82       }
83     }
84
85     if (isArray(_subscriptions)) {
86       let index = -1;
87       let len = _subscriptions.length;
88
89       while (++index < len) {
90         const sub = _subscriptions[index];
91         if (isObject(sub)) {
92           try {
93             sub.unsubscribe();
94           } catch (e) {
95             errors = errors || [];
96             if (e instanceof UnsubscriptionError) {
97               errors = errors.concat(flattenUnsubscriptionErrors(e.errors));
98             } else {
99               errors.push(e);
100             }
101           }
102         }
103       }
104     }
105
106     if (errors) {
107       throw new UnsubscriptionError(errors);
108     }
109   }
110
111   /**
112    * Adds a tear down to be called during the unsubscribe() of this
113    * Subscription. Can also be used to add a child subscription.
114    *
115    * If the tear down being added is a subscription that is already
116    * unsubscribed, is the same reference `add` is being called on, or is
117    * `Subscription.EMPTY`, it will not be added.
118    *
119    * If this subscription is already in an `closed` state, the passed
120    * tear down logic will be executed immediately.
121    *
122    * When a parent subscription is unsubscribed, any child subscriptions that were added to it are also unsubscribed.
123    *
124    * @param {TeardownLogic} teardown The additional logic to execute on
125    * teardown.
126    * @return {Subscription} Returns the Subscription used or created to be
127    * added to the inner subscriptions list. This Subscription can be used with
128    * `remove()` to remove the passed teardown logic from the inner subscriptions
129    * list.
130    */
131   add(teardown: TeardownLogic): Subscription {
132     let subscription = (<Subscription>teardown);
133
134     if (!(<any>teardown)) {
135       return Subscription.EMPTY;
136     }
137
138     switch (typeof teardown) {
139       case 'function':
140         subscription = new Subscription(<(() => void)>teardown);
141       case 'object':
142         if (subscription === this || subscription.closed || typeof subscription.unsubscribe !== 'function') {
143           // This also covers the case where `subscription` is `Subscription.EMPTY`, which is always in `closed` state.
144           return subscription;
145         } else if (this.closed) {
146           subscription.unsubscribe();
147           return subscription;
148         } else if (!(subscription instanceof Subscription)) {
149           const tmp = subscription;
150           subscription = new Subscription();
151           subscription._subscriptions = [tmp];
152         }
153         break;
154       default: {
155         throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.');
156       }
157     }
158
159     // Add `this` as parent of `subscription` if that's not already the case.
160     let { _parentOrParents } = subscription;
161     if (_parentOrParents === null) {
162       // If we don't have a parent, then set `subscription._parents` to
163       // the `this`, which is the common case that we optimize for.
164       subscription._parentOrParents = this;
165     } else if (_parentOrParents instanceof Subscription) {
166       if (_parentOrParents === this) {
167         // The `subscription` already has `this` as a parent.
168         return subscription;
169       }
170       // If there's already one parent, but not multiple, allocate an
171       // Array to store the rest of the parent Subscriptions.
172       subscription._parentOrParents = [_parentOrParents, this];
173     } else if (_parentOrParents.indexOf(this) === -1) {
174       // Only add `this` to the _parentOrParents list if it's not already there.
175       _parentOrParents.push(this);
176     } else {
177       // The `subscription` already has `this` as a parent.
178       return subscription;
179     }
180
181     // Optimize for the common case when adding the first subscription.
182     const subscriptions = this._subscriptions;
183     if (subscriptions === null) {
184       this._subscriptions = [subscription];
185     } else {
186       subscriptions.push(subscription);
187     }
188
189     return subscription;
190   }
191
192   /**
193    * Removes a Subscription from the internal list of subscriptions that will
194    * unsubscribe during the unsubscribe process of this Subscription.
195    * @param {Subscription} subscription The subscription to remove.
196    * @return {void}
197    */
198   remove(subscription: Subscription): void {
199     const subscriptions = this._subscriptions;
200     if (subscriptions) {
201       const subscriptionIndex = subscriptions.indexOf(subscription);
202       if (subscriptionIndex !== -1) {
203         subscriptions.splice(subscriptionIndex, 1);
204       }
205     }
206   }
207 }
208
209 function flattenUnsubscriptionErrors(errors: any[]) {
210  return errors.reduce((errs, err) => errs.concat((err instanceof UnsubscriptionError) ? err.errors : err), []);
211 }