project files added

This commit is contained in:
mhalfmann
2021-06-15 16:00:08 +02:00
parent e156e2f053
commit db46afa351
13928 changed files with 1569902 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
import { Subject } from './Subject';
import { Subscriber } from './Subscriber';
import { Subscription } from './Subscription';
/**
* @class AsyncSubject<T>
*/
export class AsyncSubject<T> extends Subject<T> {
private value: T = null;
private hasNext: boolean = false;
private hasCompleted: boolean = false;
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<any>): Subscription {
if (this.hasError) {
subscriber.error(this.thrownError);
return Subscription.EMPTY;
} else if (this.hasCompleted && this.hasNext) {
subscriber.next(this.value);
subscriber.complete();
return Subscription.EMPTY;
}
return super._subscribe(subscriber);
}
next(value: T): void {
if (!this.hasCompleted) {
this.value = value;
this.hasNext = true;
}
}
error(error: any): void {
if (!this.hasCompleted) {
super.error(error);
}
}
complete(): void {
this.hasCompleted = true;
if (this.hasNext) {
super.next(this.value);
}
super.complete();
}
}
+18
View File
@@ -0,0 +1,18 @@
package(default_visibility = ["//visibility:public"])
exports_files(["tsconfig.json"])
load("@build_bazel_rules_typescript//:defs.bzl", "ts_library")
ts_library(
name = "rxjs",
module_name = "rxjs",
srcs = glob(["*.ts", "**/*.ts"]),
tsconfig = "tsconfig.json",
# Specify the compile-time dependencies to run the compilation (eg. typescript)
# The default value assumes that the end-user has a target //:node_modules
# but not all users do.
# This also makes the build more reproducible, in case the user's TypeScript
# version isn't compatible.
node_modules = "@build_bazel_rules_typescript_tsc_wrapped_deps//:node_modules",
)
+40
View File
@@ -0,0 +1,40 @@
import { Subject } from './Subject';
import { Subscriber } from './Subscriber';
import { Subscription, ISubscription } from './Subscription';
import { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';
/**
* @class BehaviorSubject<T>
*/
export class BehaviorSubject<T> extends Subject<T> {
constructor(private _value: T) {
super();
}
get value(): T {
return this.getValue();
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): Subscription {
const subscription = super._subscribe(subscriber);
if (subscription && !(<ISubscription>subscription).closed) {
subscriber.next(this._value);
}
return subscription;
}
getValue(): T {
if (this.hasError) {
throw this.thrownError;
} else if (this.closed) {
throw new ObjectUnsubscribedError();
} else {
return this._value;
}
}
next(value: T): void {
super.next(this._value = value);
}
}
+29
View File
@@ -0,0 +1,29 @@
import { Subscriber } from './Subscriber';
import { OuterSubscriber } from './OuterSubscriber';
/**
* We need this JSDoc comment for affecting ESDoc.
* @ignore
* @extends {Ignored}
*/
export class InnerSubscriber<T, R> extends Subscriber<R> {
private index: number = 0;
constructor(private parent: OuterSubscriber<T, R>, private outerValue: T, private outerIndex: number) {
super();
}
protected _next(value: R): void {
this.parent.notifyNext(this.outerValue, value, this.outerIndex, this.index++, this);
}
protected _error(error: any): void {
this.parent.notifyError(error, this);
this.unsubscribe();
}
protected _complete(): void {
this.parent.notifyComplete(this);
this.unsubscribe();
}
}
+202
View File
@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright (c) 2015-2017 Google, Inc., Netflix, Inc., Microsoft Corp. and contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+451
View File
@@ -0,0 +1,451 @@
/*
* This file and its definitions are needed just so that ESDoc sees these
* JSDoc documentation comments. Originally they were meant for some TypeScript
* interfaces, but TypeScript strips away JSDoc comments near interfaces. Hence,
* we need these bogus classes, which are not stripped away. This file on the
* other hand, is not included in the release bundle.
*/
import { TeardownLogic } from './Subscription';
import { Observable } from './Observable';
import './observable/dom/MiscJSDoc';
import { Observer } from './Observer';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class ObservableDoc {
/**
* Creates a new Observable, that will execute the specified function when an
* {@link Observer} subscribes to it.
*
* <span class="informal">Create custom Observable, that does whatever you like.</span>
*
* <img src="./img/create.png" width="100%">
*
* `create` converts an `onSubscription` function to an actual Observable.
* Whenever someone subscribes to that Observable, the function will be called
* with an {@link Observer} instance as a first and only parameter. `onSubscription` should
* then invoke the Observers `next`, `error` and `complete` methods.
*
* Calling `next` with a value will emit that value to the observer. Calling `complete`
* means that Observable finished emitting and will not do anything else.
* Calling `error` means that something went wrong - value passed to `error` method should
* provide details on what exactly happened.
*
* A well-formed Observable can emit as many values as it needs via `next` method,
* but `complete` and `error` methods can be called only once and nothing else can be called
* thereafter. If you try to invoke `next`, `complete` or `error` methods after created
* Observable already completed or ended with an error, these calls will be ignored to
* preserve so called *Observable Contract*. Note that you are not required to call
* `complete` at any point - it is perfectly fine to create an Observable that never ends,
* depending on your needs.
*
* `onSubscription` can optionally return either a function or an object with
* `unsubscribe` method. In both cases function or method will be called when
* subscription to Observable is being cancelled and should be used to clean up all
* resources. So, for example, if you are using `setTimeout` in your custom
* Observable, when someone unsubscribes, you can clear planned timeout, so that
* it does not fire needlessly and browser (or other environment) does not waste
* computing power on timing event that no one will listen to anyways.
*
* Most of the times you should not need to use `create`, because existing
* operators allow you to create an Observable for most of the use cases.
* That being said, `create` is low-level mechanism allowing you to create
* any Observable, if you have very specific needs.
*
* **TypeScript signature issue**
*
* Because Observable extends class which already has defined static `create` function,
* but with different type signature, it was impossible to assign proper signature to
* `Observable.create`. Because of that, it has very general type `Function` and thus
* function passed to `create` will not be type checked, unless you explicitly state
* what signature it should have.
*
* When using TypeScript we recommend to declare type signature of function passed to
* `create` as `(observer: Observer) => TeardownLogic`, where {@link Observer}
* and {@link TeardownLogic} are interfaces provided by the library.
*
* @example <caption>Emit three numbers, then complete.</caption>
* var observable = Rx.Observable.create(function (observer) {
* observer.next(1);
* observer.next(2);
* observer.next(3);
* observer.complete();
* });
* observable.subscribe(
* value => console.log(value),
* err => {},
* () => console.log('this is the end')
* );
*
* // Logs
* // 1
* // 2
* // 3
* // "this is the end"
*
*
* @example <caption>Emit an error</caption>
* const observable = Rx.Observable.create((observer) => {
* observer.error('something went really wrong...');
* });
*
* observable.subscribe(
* value => console.log(value), // will never be called
* err => console.log(err),
* () => console.log('complete') // will never be called
* );
*
* // Logs
* // "something went really wrong..."
*
*
* @example <caption>Return unsubscribe function</caption>
*
* const observable = Rx.Observable.create(observer => {
* const id = setTimeout(() => observer.next('...'), 5000); // emit value after 5s
*
* return () => { clearTimeout(id); console.log('cleared!'); };
* });
*
* const subscription = observable.subscribe(value => console.log(value));
*
* setTimeout(() => subscription.unsubscribe(), 3000); // cancel subscription after 3s
*
* // Logs:
* // "cleared!" after 3s
*
* // Never logs "..."
*
*
* @see {@link empty}
* @see {@link never}
* @see {@link of}
* @see {@link throw}
*
* @param {function(observer: Observer): TeardownLogic} onSubscription A
* function that accepts an Observer, and invokes its `next`,
* `error`, and `complete` methods as appropriate, and optionally returns some
* logic for cleaning up resources.
* @return {Observable} An Observable that, whenever subscribed, will execute the
* specified function.
* @static true
* @name create
* @owner Observable
*/
static create<T>(onSubscription: <R>(observer: Observer<R>) => TeardownLogic): Observable<T> {
return new Observable<T>(onSubscription);
};
}
/**
* An interface for a consumer of push-based notifications delivered by an
* {@link Observable}.
*
* ```ts
* interface Observer<T> {
* closed?: boolean;
* next: (value: T) => void;
* error: (err: any) => void;
* complete: () => void;
* }
* ```
*
* An object conforming to the Observer interface is usually
* given to the `observable.subscribe(observer)` method, and the Observable will
* call the Observer's `next(value)` method to provide notifications. A
* well-behaved Observable will call an Observer's `complete()` method exactly
* once or the Observer's `error(err)` method exactly once, as the last
* notification delivered.
*
* @interface
* @name Observer
* @noimport true
*/
export class ObserverDoc<T> {
/**
* An optional flag to indicate whether this Observer, when used as a
* subscriber, has already been unsubscribed from its Observable.
* @type {boolean}
*/
closed: boolean = false;
/**
* The callback to receive notifications of type `next` from the Observable,
* with a value. The Observable may call this method 0 or more times.
* @param {T} value The `next` value.
* @return {void}
*/
next(value: T): void {
return void 0;
}
/**
* The callback to receive notifications of type `error` from the Observable,
* with an attached {@link Error}. Notifies the Observer that the Observable
* has experienced an error condition.
* @param {any} err The `error` exception.
* @return {void}
*/
error(err: any): void {
return void 0;
}
/**
* The callback to receive a valueless notification of type `complete` from
* the Observable. Notifies the Observer that the Observable has finished
* sending push-based notifications.
* @return {void}
*/
complete(): void {
return void 0;
}
}
/**
* `SubscribableOrPromise` interface describes values that behave like either
* Observables or Promises. Every operator that accepts arguments annotated
* with this interface, can be also used with parameters that are not necessarily
* RxJS Observables.
*
* Following types of values might be passed to operators expecting this interface:
*
* ## Observable
*
* RxJS {@link Observable} instance.
*
* ## Observable-like (Subscribable)
*
* This might be any object that has `Symbol.observable` method. This method,
* when called, should return object with `subscribe` method on it, which should
* behave the same as RxJS `Observable.subscribe`.
*
* `Symbol.observable` is part of https://github.com/tc39/proposal-observable proposal.
* Since currently it is not supported natively, and every symbol is equal only to itself,
* you should use https://github.com/blesh/symbol-observable polyfill, when implementing
* custom Observable-likes.
*
* **TypeScript Subscribable interface issue**
*
* Although TypeScript interface claims that Subscribable is an object that has `subscribe`
* method declared directly on it, passing custom objects that have `subscribe`
* method but not `Symbol.observable` method will fail at runtime. Conversely, passing
* objects with `Symbol.observable` but without `subscribe` will fail at compile time
* (if you use TypeScript).
*
* TypeScript has problem supporting interfaces with methods defined as symbol
* properties. To get around that, you should implement `subscribe` directly on
* passed object, and make `Symbol.observable` method simply return `this`. That way
* everything will work as expected, and compiler will not complain. If you really
* do not want to put `subscribe` directly on your object, you will have to type cast
* it to `any`, before passing it to an operator.
*
* When this issue is resolved, Subscribable interface will only permit Observable-like
* objects with `Symbol.observable` defined, no matter if they themselves implement
* `subscribe` method or not.
*
* ## ES6 Promise
*
* Promise can be interpreted as Observable that emits value and completes
* when it is resolved or errors when it is rejected.
*
* ## Promise-like (Thenable)
*
* Promises passed to operators do not have to be native ES6 Promises.
* They can be implementations from popular Promise libraries, polyfills
* or even custom ones. They just need to have `then` method that works
* as the same as ES6 Promise `then`.
*
* @example <caption>Use merge and then map with non-RxJS observable</caption>
* const nonRxJSObservable = {
* subscribe(observer) {
* observer.next(1000);
* observer.complete();
* },
* [Symbol.observable]() {
* return this;
* }
* };
*
* Rx.Observable.merge(nonRxJSObservable)
* .map(value => "This value is " + value)
* .subscribe(result => console.log(result)); // Logs "This value is 1000"
*
*
* @example <caption>Use combineLatest with ES6 Promise</caption>
* Rx.Observable.combineLatest(Promise.resolve(5), Promise.resolve(10), Promise.resolve(15))
* .subscribe(
* value => console.log(value),
* err => {},
* () => console.log('the end!')
* );
* // Logs
* // [5, 10, 15]
* // "the end!"
*
*
* @interface
* @name SubscribableOrPromise
* @noimport true
*/
export class SubscribableOrPromiseDoc<T> {
}
/**
* `ObservableInput` interface describes all values that are either an
* {@link SubscribableOrPromise} or some kind of collection of values that
* can be transformed to Observable emitting that values. Every operator that
* accepts arguments annotated with this interface, can be also used with
* parameters that are not necessarily RxJS Observables.
*
* `ObservableInput` extends {@link SubscribableOrPromise} with following types:
*
* ## Array
*
* Arrays can be interpreted as observables that emit all values in array one by one,
* from left to right, and then complete immediately.
*
* ## Array-like
*
* Arrays passed to operators do not have to be built-in JavaScript Arrays. They
* can be also, for example, `arguments` property available inside every function,
* [DOM NodeList](https://developer.mozilla.org/pl/docs/Web/API/NodeList),
* or, actually, any object that has `length` property (which is a number)
* and stores values under non-negative (zero and up) integers.
*
* ## ES6 Iterable
*
* Operators will accept both built-in and custom ES6 Iterables, by treating them as
* observables that emit all its values in order of iteration and then complete
* when iteration ends. Note that contrary to arrays, Iterables do not have to
* necessarily be finite, so creating Observables that never complete is possible as well.
*
* Note that you can make iterator an instance of Iterable by having it return itself
* in `Symbol.iterator` method. It means that every operator accepting Iterables accepts,
* though indirectly, iterators themselves as well. All native ES6 iterators are instances
* of Iterable by default, so you do not have to implement their `Symbol.iterator` method
* yourself.
*
* **TypeScript Iterable interface issue**
*
* TypeScript `ObservableInput` interface actually lacks type signature for Iterables,
* because of issues it caused in some projects (see [this issue](https://github.com/ReactiveX/rxjs/issues/2306)).
* If you want to use Iterable as argument for operator, cast it to `any` first.
* Remember of course that, because of casting, you have to yourself ensure that passed
* argument really implements said interface.
*
*
* @example <caption>Use merge with arrays</caption>
* Rx.Observable.merge([1, 2], [4], [5, 6])
* .subscribe(
* value => console.log(value),
* err => {},
* () => console.log('ta dam!')
* );
*
* // Logs
* // 1
* // 2
* // 3
* // 4
* // 5
* // 6
* // "ta dam!"
*
*
* @example <caption>Use merge with array-like</caption>
* Rx.Observable.merge({0: 1, 1: 2, length: 2}, {0: 3, length: 1})
* .subscribe(
* value => console.log(value),
* err => {},
* () => console.log('nice, huh?')
* );
*
* // Logs
* // 1
* // 2
* // 3
* // "nice, huh?"
*
* @example <caption>Use merge with an Iterable (Map)</caption>
* const firstMap = new Map([[1, 'a'], [2, 'b']]);
* const secondMap = new Map([[3, 'c'], [4, 'd']]);
*
* Rx.Observable.merge(
* firstMap, // pass Iterable
* secondMap.values() // pass iterator, which is itself an Iterable
* ).subscribe(
* value => console.log(value),
* err => {},
* () => console.log('yup!')
* );
*
* // Logs
* // [1, "a"]
* // [2, "b"]
* // "c"
* // "d"
* // "yup!"
*
* @example <caption>Use from with generator (returning infinite iterator)</caption>
* // infinite stream of incrementing numbers
* const infinite = function* () {
* let i = 0;
*
* while (true) {
* yield i++;
* }
* };
*
* Rx.Observable.from(infinite())
* .take(3) // only take 3, cause this is infinite
* .subscribe(
* value => console.log(value),
* err => {},
* () => console.log('ta dam!')
* );
*
* // Logs
* // 0
* // 1
* // 2
* // "ta dam!"
*
* @interface
* @name ObservableInput
* @noimport true
*/
export class ObservableInputDoc<T> {
}
/**
*
* This interface describes what should be returned by function passed to Observable
* constructor or static {@link create} function. Value of that interface will be used
* to cancel subscription for given Observable.
*
* `TeardownLogic` can be:
*
* ## Function
*
* Function that takes no parameters. When consumer of created Observable calls `unsubscribe`,
* that function will be called
*
* ## AnonymousSubscription
*
* `AnonymousSubscription` is simply an object with `unsubscribe` method on it. That method
* will work the same as function
*
* ## void
*
* If created Observable does not have any resources to clean up, function does not have to
* return anything.
*
* @interface
* @name TeardownLogic
* @noimport true
*/
export class TeardownLogicDoc {
}
+131
View File
@@ -0,0 +1,131 @@
import { PartialObserver } from './Observer';
import { Observable } from './Observable';
/**
* Represents a push-based event or value that an {@link Observable} can emit.
* This class is particularly useful for operators that manage notifications,
* like {@link materialize}, {@link dematerialize}, {@link observeOn}, and
* others. Besides wrapping the actual delivered value, it also annotates it
* with metadata of, for instance, what type of push message it is (`next`,
* `error`, or `complete`).
*
* @see {@link materialize}
* @see {@link dematerialize}
* @see {@link observeOn}
*
* @class Notification<T>
*/
export class Notification<T> {
hasValue: boolean;
constructor(public kind: string, public value?: T, public error?: any) {
this.hasValue = kind === 'N';
}
/**
* Delivers to the given `observer` the value wrapped by this Notification.
* @param {Observer} observer
* @return
*/
observe(observer: PartialObserver<T>): any {
switch (this.kind) {
case 'N':
return observer.next && observer.next(this.value);
case 'E':
return observer.error && observer.error(this.error);
case 'C':
return observer.complete && observer.complete();
}
}
/**
* Given some {@link Observer} callbacks, deliver the value represented by the
* current Notification to the correctly corresponding callback.
* @param {function(value: T): void} next An Observer `next` callback.
* @param {function(err: any): void} [error] An Observer `error` callback.
* @param {function(): void} [complete] An Observer `complete` callback.
* @return {any}
*/
do(next: (value: T) => void, error?: (err: any) => void, complete?: () => void): any {
const kind = this.kind;
switch (kind) {
case 'N':
return next && next(this.value);
case 'E':
return error && error(this.error);
case 'C':
return complete && complete();
}
}
/**
* Takes an Observer or its individual callback functions, and calls `observe`
* or `do` methods accordingly.
* @param {Observer|function(value: T): void} nextOrObserver An Observer or
* the `next` callback.
* @param {function(err: any): void} [error] An Observer `error` callback.
* @param {function(): void} [complete] An Observer `complete` callback.
* @return {any}
*/
accept(nextOrObserver: PartialObserver<T> | ((value: T) => void), error?: (err: any) => void, complete?: () => void) {
if (nextOrObserver && typeof (<PartialObserver<T>>nextOrObserver).next === 'function') {
return this.observe(<PartialObserver<T>>nextOrObserver);
} else {
return this.do(<(value: T) => void>nextOrObserver, error, complete);
}
}
/**
* Returns a simple Observable that just delivers the notification represented
* by this Notification instance.
* @return {any}
*/
toObservable(): Observable<T> {
const kind = this.kind;
switch (kind) {
case 'N':
return Observable.of(this.value);
case 'E':
return Observable.throw(this.error);
case 'C':
return Observable.empty<T>();
}
throw new Error('unexpected notification kind value');
}
private static completeNotification: Notification<any> = new Notification('C');
private static undefinedValueNotification: Notification<any> = new Notification('N', undefined);
/**
* A shortcut to create a Notification instance of the type `next` from a
* given value.
* @param {T} value The `next` value.
* @return {Notification<T>} The "next" Notification representing the
* argument.
*/
static createNext<T>(value: T): Notification<T> {
if (typeof value !== 'undefined') {
return new Notification('N', value);
}
return Notification.undefinedValueNotification;
}
/**
* A shortcut to create a Notification instance of the type `error` from a
* given error.
* @param {any} [err] The `error` error.
* @return {Notification<T>} The "error" Notification representing the
* argument.
*/
static createError<T>(err?: any): Notification<T> {
return new Notification('E', undefined, err);
}
/**
* A shortcut to create a Notification instance of the type `complete`.
* @return {Notification<any>} The valueless "complete" Notification.
*/
static createComplete(): Notification<any> {
return Notification.completeNotification;
}
}
+355
View File
@@ -0,0 +1,355 @@
import { PartialObserver } from './Observer';
import { Operator } from './Operator';
import { Subscriber } from './Subscriber';
import { Subscription, AnonymousSubscription, TeardownLogic } from './Subscription';
import { root } from './util/root';
import { toSubscriber } from './util/toSubscriber';
import { IfObservable } from './observable/IfObservable';
import { ErrorObservable } from './observable/ErrorObservable';
import { observable as Symbol_observable } from './symbol/observable';
import { OperatorFunction } from './interfaces';
import { pipeFromArray } from './util/pipe';
export interface Subscribable<T> {
subscribe(observerOrNext?: PartialObserver<T> | ((value: T) => void),
error?: (error: any) => void,
complete?: () => void): AnonymousSubscription;
}
export type SubscribableOrPromise<T> = Subscribable<T> | PromiseLike<T>;
export type ObservableInput<T> = SubscribableOrPromise<T> | ArrayLike<T>;
/**
* A representation of any set of values over any amount of time. This is the most basic building block
* of RxJS.
*
* @class Observable<T>
*/
export class Observable<T> implements Subscribable<T> {
public _isScalar: boolean = false;
/** @deprecated internal use only */ public source: Observable<any>;
protected operator: Operator<any, T>;
/**
* @constructor
* @param {Function} subscribe the function that is called when the Observable is
* initially subscribed to. This function is given a Subscriber, to which new values
* can be `next`ed, or an `error` method can be called to raise an error, or
* `complete` can be called to notify of a successful completion.
*/
constructor(subscribe?: (this: Observable<T>, subscriber: Subscriber<T>) => TeardownLogic) {
if (subscribe) {
this._subscribe = subscribe;
}
}
// HACK: Since TypeScript inherits static properties too, we have to
// fight against TypeScript here so Subject can have a different static create signature
/**
* Creates a new cold Observable by calling the Observable constructor
* @static true
* @owner Observable
* @method create
* @param {Function} subscribe? the subscriber function to be passed to the Observable constructor
* @return {Observable} a new cold observable
*/
static create: Function = <T>(subscribe?: (subscriber: Subscriber<T>) => TeardownLogic) => {
return new Observable<T>(subscribe);
}
/**
* Creates a new Observable, with this Observable as the source, and the passed
* operator defined as the new observable's operator.
* @method lift
* @param {Operator} operator the operator defining the operation to take on the observable
* @return {Observable} a new observable with the Operator applied
*/
lift<R>(operator: Operator<T, R>): Observable<R> {
const observable = new Observable<R>();
observable.source = this;
observable.operator = operator;
return observable;
}
subscribe(observer?: PartialObserver<T>): Subscription;
subscribe(next?: (value: T) => void, error?: (error: any) => void, complete?: () => void): Subscription;
/**
* Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.
*
* <span class="informal">Use it when you have all these Observables, but still nothing is happening.</span>
*
* `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It
* might be for example a function that you passed to a {@link create} static factory, but most of the time it is
* a library implementation, which defines what and when will be emitted by an Observable. This means that calling
* `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often
* thought.
*
* Apart from starting the execution of an Observable, this method allows you to listen for values
* that an Observable emits, as well as for when it completes or errors. You can achieve this in two
* following ways.
*
* The first way is creating an object that implements {@link Observer} interface. It should have methods
* defined by that interface, but note that it should be just a regular JavaScript object, which you can create
* yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular do
* not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also
* that your object does not have to implement all methods. If you find yourself creating a method that doesn't
* do anything, you can simply omit it. Note however, that if `error` method is not provided, all errors will
* be left uncaught.
*
* The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.
* This means you can provide three functions as arguments to `subscribe`, where first function is equivalent
* of a `next` method, second of an `error` method and third of a `complete` method. Just as in case of Observer,
* if you do not need to listen for something, you can omit a function, preferably by passing `undefined` or `null`,
* since `subscribe` recognizes these functions by where they were placed in function call. When it comes
* to `error` function, just as before, if not provided, errors emitted by an Observable will be thrown.
*
* Whatever style of calling `subscribe` you use, in both cases it returns a Subscription object.
* This object allows you to call `unsubscribe` on it, which in turn will stop work that an Observable does and will clean
* up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback
* provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.
*
* Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.
* It is an Observable itself that decides when these functions will be called. For example {@link of}
* by default emits all its values synchronously. Always check documentation for how given Observable
* will behave when subscribed and if its default behavior can be modified with a {@link Scheduler}.
*
* @example <caption>Subscribe with an Observer</caption>
* const sumObserver = {
* sum: 0,
* next(value) {
* console.log('Adding: ' + value);
* this.sum = this.sum + value;
* },
* error() { // We actually could just remove this method,
* }, // since we do not really care about errors right now.
* complete() {
* console.log('Sum equals: ' + this.sum);
* }
* };
*
* Rx.Observable.of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.
* .subscribe(sumObserver);
*
* // Logs:
* // "Adding: 1"
* // "Adding: 2"
* // "Adding: 3"
* // "Sum equals: 6"
*
*
* @example <caption>Subscribe with functions</caption>
* let sum = 0;
*
* Rx.Observable.of(1, 2, 3)
* .subscribe(
* function(value) {
* console.log('Adding: ' + value);
* sum = sum + value;
* },
* undefined,
* function() {
* console.log('Sum equals: ' + sum);
* }
* );
*
* // Logs:
* // "Adding: 1"
* // "Adding: 2"
* // "Adding: 3"
* // "Sum equals: 6"
*
*
* @example <caption>Cancel a subscription</caption>
* const subscription = Rx.Observable.interval(1000).subscribe(
* num => console.log(num),
* undefined,
* () => console.log('completed!') // Will not be called, even
* ); // when cancelling subscription
*
*
* setTimeout(() => {
* subscription.unsubscribe();
* console.log('unsubscribed!');
* }, 2500);
*
* // Logs:
* // 0 after 1s
* // 1 after 2s
* // "unsubscribed!" after 2.5s
*
*
* @param {Observer|Function} observerOrNext (optional) Either an observer with methods to be called,
* or the first of three possible handlers, which is the handler for each value emitted from the subscribed
* Observable.
* @param {Function} error (optional) A handler for a terminal event resulting from an error. If no error handler is provided,
* the error will be thrown as unhandled.
* @param {Function} complete (optional) A handler for a terminal event resulting from successful completion.
* @return {ISubscription} a subscription reference to the registered handlers
* @method subscribe
*/
subscribe(observerOrNext?: PartialObserver<T> | ((value: T) => void),
error?: (error: any) => void,
complete?: () => void): Subscription {
const { operator } = this;
const sink = toSubscriber(observerOrNext, error, complete);
if (operator) {
operator.call(sink, this.source);
} else {
sink.add(this.source || !sink.syncErrorThrowable ? this._subscribe(sink) : this._trySubscribe(sink));
}
if (sink.syncErrorThrowable) {
sink.syncErrorThrowable = false;
if (sink.syncErrorThrown) {
throw sink.syncErrorValue;
}
}
return sink;
}
protected _trySubscribe(sink: Subscriber<T>): TeardownLogic {
try {
return this._subscribe(sink);
} catch (err) {
sink.syncErrorThrown = true;
sink.syncErrorValue = err;
sink.error(err);
}
}
/**
* @method forEach
* @param {Function} next a handler for each value emitted by the observable
* @param {PromiseConstructor} [PromiseCtor] a constructor function used to instantiate the Promise
* @return {Promise} a promise that either resolves on observable completion or
* rejects with the handled error
*/
forEach(next: (value: T) => void, PromiseCtor?: typeof Promise): Promise<void> {
if (!PromiseCtor) {
if (root.Rx && root.Rx.config && root.Rx.config.Promise) {
PromiseCtor = root.Rx.config.Promise;
} else if (root.Promise) {
PromiseCtor = root.Promise;
}
}
if (!PromiseCtor) {
throw new Error('no Promise impl found');
}
return new PromiseCtor<void>((resolve, reject) => {
// Must be declared in a separate statement to avoid a RefernceError when
// accessing subscription below in the closure due to Temporal Dead Zone.
let subscription: Subscription;
subscription = this.subscribe((value) => {
if (subscription) {
// if there is a subscription, then we can surmise
// the next handling is asynchronous. Any errors thrown
// need to be rejected explicitly and unsubscribe must be
// called manually
try {
next(value);
} catch (err) {
reject(err);
subscription.unsubscribe();
}
} else {
// if there is NO subscription, then we're getting a nexted
// value synchronously during subscription. We can just call it.
// If it errors, Observable's `subscribe` will ensure the
// unsubscription logic is called, then synchronously rethrow the error.
// After that, Promise will trap the error and send it
// down the rejection path.
next(value);
}
}, reject, resolve);
});
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<any>): TeardownLogic {
return this.source.subscribe(subscriber);
}
// `if` and `throw` are special snow flakes, the compiler sees them as reserved words
static if: typeof IfObservable.create;
static throw: typeof ErrorObservable.create;
/**
* An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable
* @method Symbol.observable
* @return {Observable} this instance of the observable
*/
[Symbol_observable]() {
return this;
}
/* tslint:disable:max-line-length */
pipe(): Observable<T>
pipe<A>(op1: OperatorFunction<T, A>): Observable<A>
pipe<A, B>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>): Observable<B>
pipe<A, B, C>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>): Observable<C>
pipe<A, B, C, D>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>): Observable<D>
pipe<A, B, C, D, E>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>, op5: OperatorFunction<D, E>): Observable<E>
pipe<A, B, C, D, E, F>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>, op5: OperatorFunction<D, E>, op6: OperatorFunction<E, F>): Observable<F>
pipe<A, B, C, D, E, F, G>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>, op5: OperatorFunction<D, E>, op6: OperatorFunction<E, F>, op7: OperatorFunction<F, G>): Observable<G>
pipe<A, B, C, D, E, F, G, H>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>, op5: OperatorFunction<D, E>, op6: OperatorFunction<E, F>, op7: OperatorFunction<F, G>, op8: OperatorFunction<G, H>): Observable<H>
pipe<A, B, C, D, E, F, G, H, I>(op1: OperatorFunction<T, A>, op2: OperatorFunction<A, B>, op3: OperatorFunction<B, C>, op4: OperatorFunction<C, D>, op5: OperatorFunction<D, E>, op6: OperatorFunction<E, F>, op7: OperatorFunction<F, G>, op8: OperatorFunction<G, H>, op9: OperatorFunction<H, I>): Observable<I>
pipe<R>(...operations: OperatorFunction<T, R>[]): Observable<R>
/* tslint:enable:max-line-length */
/**
* Used to stitch together functional operators into a chain.
* @method pipe
* @return {Observable} the Observable result of all of the operators having
* been called in the order they were passed in.
*
* @example
*
* import { map, filter, scan } from 'rxjs/operators';
*
* Rx.Observable.interval(1000)
* .pipe(
* filter(x => x % 2 === 0),
* map(x => x + x),
* scan((acc, x) => acc + x)
* )
* .subscribe(x => console.log(x))
*/
pipe<R>(...operations: OperatorFunction<T, R>[]): Observable<R> {
if (operations.length === 0) {
return this as any;
}
return pipeFromArray(operations)(this);
}
/* tslint:disable:max-line-length */
toPromise<T>(this: Observable<T>): Promise<T>;
toPromise<T>(this: Observable<T>, PromiseCtor: typeof Promise): Promise<T>;
toPromise<T>(this: Observable<T>, PromiseCtor: PromiseConstructorLike): Promise<T>;
/* tslint:enable:max-line-length */
toPromise(PromiseCtor?: PromiseConstructorLike) {
if (!PromiseCtor) {
if (root.Rx && root.Rx.config && root.Rx.config.Promise) {
PromiseCtor = root.Rx.config.Promise;
} else if (root.Promise) {
PromiseCtor = root.Promise;
}
}
if (!PromiseCtor) {
throw new Error('no Promise impl found');
}
return new PromiseCtor((resolve, reject) => {
let value: any;
this.subscribe((x: T) => value = x, (err: any) => reject(err), () => resolve(value));
}) as Promise<T>;
}
}
+36
View File
@@ -0,0 +1,36 @@
export interface NextObserver<T> {
closed?: boolean;
next: (value: T) => void;
error?: (err: any) => void;
complete?: () => void;
}
export interface ErrorObserver<T> {
closed?: boolean;
next?: (value: T) => void;
error: (err: any) => void;
complete?: () => void;
}
export interface CompletionObserver<T> {
closed?: boolean;
next?: (value: T) => void;
error?: (err: any) => void;
complete: () => void;
}
export type PartialObserver<T> = NextObserver<T> | ErrorObserver<T> | CompletionObserver<T>;
export interface Observer<T> {
closed?: boolean;
next: (value: T) => void;
error: (err: any) => void;
complete: () => void;
}
export const empty: Observer<any> = {
closed: true,
next(value: any): void { /* noop */},
error(err: any): void { throw err; },
complete(): void { /*noop*/ }
};
+6
View File
@@ -0,0 +1,6 @@
import { Subscriber } from './Subscriber';
import { TeardownLogic } from './Subscription';
export interface Operator<T, R> {
call(subscriber: Subscriber<R>, source: any): TeardownLogic;
}
+23
View File
@@ -0,0 +1,23 @@
import { Subscriber } from './Subscriber';
import { InnerSubscriber } from './InnerSubscriber';
/**
* We need this JSDoc comment for affecting ESDoc.
* @ignore
* @extends {Ignored}
*/
export class OuterSubscriber<T, R> extends Subscriber<T> {
notifyNext(outerValue: T, innerValue: R,
outerIndex: number, innerIndex: number,
innerSub: InnerSubscriber<T, R>): void {
this.destination.next(innerValue);
}
notifyError(error: any, innerSub: InnerSubscriber<T, R>): void {
this.destination.error(error);
}
notifyComplete(innerSub: InnerSubscriber<T, R>): void {
this.destination.complete();
}
}
+206
View File
@@ -0,0 +1,206 @@
[![Build Status](https://travis-ci.org/ReactiveX/rxjs.svg?branch=master)](https://travis-ci.org/ReactiveX/rxjs)
[![Coverage Status](https://coveralls.io/repos/github/ReactiveX/rxjs/badge.svg?branch=master)](https://coveralls.io/github/ReactiveX/rxjs?branch=master)
[![npm version](https://badge.fury.io/js/%40reactivex%2Frxjs.svg)](http://badge.fury.io/js/%40reactivex%2Frxjs)
[![Join the chat at https://gitter.im/Reactive-Extensions/RxJS](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Reactive-Extensions/RxJS?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Selenium Test Status](https://saucelabs.com/browser-matrix/rxjs5.svg)](https://saucelabs.com/u/rxjs5)
# RxJS 5
Reactive Extensions Library for JavaScript. This is a rewrite of [Reactive-Extensions/RxJS](https://github.com/Reactive-Extensions/RxJS) and is the latest production-ready version of RxJS. This rewrite is meant to have better performance, better modularity, better debuggable call stacks, while staying mostly backwards compatible, with some breaking changes that reduce the API surface.
[Apache 2.0 License](LICENSE.txt)
- [Code of Conduct](CODE_OF_CONDUCT.md)
- [Contribution Guidelines](CONTRIBUTING.md)
- [Maintainer Guidelines](doc/maintainer-guidelines.md)
- [Creating Operators](doc/operator-creation.md)
- [Migrating From RxJS 4 to RxJS 5](MIGRATION.md)
- [API Documentation (WIP)](http://reactivex.io/rxjs)
## Versions In This Repository
- [master](https://github.com/ReactiveX/rxjs/commits/master) - commits that will be included in the next _minor_ or _patch_ release
- [next](https://github.com/ReactiveX/rxjs/commits/next) - commits that will be included in the next _major_ release (breaking changes)
Most PRs should be made to **master**, unless you know it is a breaking change.
## Important
By contributing or commenting on issues in this repository, whether you've read them or not, you're agreeing to the [Contributor Code of Conduct](CODE_OF_CONDUCT.md). Much like traffic laws, ignorance doesn't grant you immunity.
## Installation and Usage
### ES6 via npm
```sh
npm install rxjs
```
To import the entire core set of functionality:
```js
import Rx from 'rxjs/Rx';
Rx.Observable.of(1,2,3)
```
To import only what you need by patching (this is useful for size-sensitive bundling):
```js
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/map';
Observable.of(1,2,3).map(x => x + '!!!'); // etc
```
To import what you need and use it with proposed [bind operator](https://github.com/tc39/proposal-bind-operator):
> Note: This additional syntax requires [transpiler support](http://babeljs.io/docs/plugins/transform-function-bind/) and this syntax may be completely withdrawn from TC39 without notice! Use at your own risk.
```js
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { map } from 'rxjs/operator/map';
Observable::of(1,2,3)::map(x => x + '!!!'); // etc
```
### CommonJS via npm
To install this library for CommonJS (CJS) usage, use the following command:
```sh
npm install rxjs
```
Import all core functionality:
```js
var Rx = require('rxjs/Rx');
Rx.Observable.of(1,2,3); // etc
```
Import only what you need and patch Observable (this is useful in size-sensitive bundling scenarios):
```js
var Observable = require('rxjs/Observable').Observable;
// patch Observable with appropriate methods
require('rxjs/add/observable/of');
require('rxjs/add/operator/map');
Observable.of(1,2,3).map(function (x) { return x + '!!!'; }); // etc
```
Import operators and use them _manually_ you can do the following (this is also useful for bundling):
```js
var of = require('rxjs/observable/of').of;
var map = require('rxjs/operator/map').map;
map.call(of(1,2,3), function (x) { return x + '!!!'; });
```
You can also use the above method to build your own Observable and export it from your own module.
### All Module Types (CJS/ES6/AMD/TypeScript) via npm
To install this library via [npm](https://www.npmjs.org) **version 3**, use the following command:
```sh
npm install @reactivex/rxjs
```
This will include CJS/Global builds and can be used for all module types.
If you are using npm **version 2** before this library has achieved a stable version, you need to specify the library version explicitly:
```sh
npm install @reactivex/rxjs@5.0.0
```
### CDN
For CDN, you can use [unpkg](https://unpkg.com/):
https://unpkg.com/rxjs@version/bundles/Rx.min.js
*replace **version** with the current version. See [docs](http://reactivex.io/rxjs/manual/installation.html#cdn).*
#### Node.js Usage:
```js
var Rx = require('@reactivex/rxjs');
Rx.Observable.of('hello world')
.subscribe(function(x) { console.log(x); });
```
## Goals
- Provide better performance than preceding versions of RxJS
- To model/follow the [Observable Spec Proposal](https://github.com/zenparsing/es-observable) to the observable.
- Provide more modular file structure in a variety of formats
- Provide more debuggable call stacks than preceding versions of RxJS
## Building/Testing
The build and test structure is fairly primitive at the moment. There are various npm scripts that can be run:
- build_es6: Transpiles the TypeScript files from `src/` to `dist/es6`
- build_cjs: Transpiles the ES6 files from `dist/es6` to `dist/cjs`
- build_amd: Transpiles the ES6 files from `dist/es6` to `dist/amd`
- build_global: Transpiles/Bundles the CommonJS files from `dist/cjs` to `dist/global/Rx.js`
- build_all: Performs all of the above in the proper order.
- build_test: builds ES6, then CommonJS, then runs the tests with `jasmine`
- build_perf: builds ES6, CommonJS, then global, then runs the performance tests with `protractor`
- build_docs: generates API documentation from `dist/es6` to `dist/docs`
- build_cover: runs `istanbul` code coverage against test cases
- test: runs tests with `jasmine`, must have built prior to running.
- tests2png: generates PNG marble diagrams from test cases.
`npm run info` will list available script.
### Example
```sh
# build all the things!
npm run build_all
```
## Performance Tests
Run `npm run build_perf` or `npm run perf` to run the performance tests with `protractor`.
Run `npm run perf_micro` to run micro performance test benchmarking operator.
## Adding documentation
RxNext uses [ESDoc](https://esdoc.org/) to generate API documentation. Refer to ESDoc's documentation for syntax. Run `npm run build_docs` to generate.
## Generating PNG marble diagrams
The script `npm run tests2png` requires some native packages installed locally: `imagemagick`, `graphicsmagick`, and `ghostscript`.
For Mac OS X with [Homebrew](http://brew.sh/):
- `brew install imagemagick`
- `brew install graphicsmagick`
- `brew install ghostscript`
- You may need to install the Ghostscript fonts manually:
- Download the tarball from the [gs-fonts project](https://sourceforge.net/projects/gs-fonts)
- `mkdir -p /usr/local/share/ghostscript && tar zxvf /path/to/ghostscript-fonts.tar.gz -C /usr/local/share/ghostscript`
For Debian Linux:
- `sudo add-apt-repository ppa:dhor/myway`
- `apt-get install imagemagick`
- `apt-get install graphicsmagick`
- `apt-get install ghostscript`
For Windows and other Operating Systems, check the download instructions here:
- http://imagemagick.org
- http://www.graphicsmagick.org
- http://www.ghostscript.com/
+104
View File
@@ -0,0 +1,104 @@
import { Subject } from './Subject';
import { IScheduler } from './Scheduler';
import { queue } from './scheduler/queue';
import { Subscriber } from './Subscriber';
import { Subscription } from './Subscription';
import { ObserveOnSubscriber } from './operators/observeOn';
import { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';
import { SubjectSubscription } from './SubjectSubscription';
/**
* @class ReplaySubject<T>
*/
export class ReplaySubject<T> extends Subject<T> {
private _events: ReplayEvent<T>[] = [];
private _bufferSize: number;
private _windowTime: number;
constructor(bufferSize: number = Number.POSITIVE_INFINITY,
windowTime: number = Number.POSITIVE_INFINITY,
private scheduler?: IScheduler) {
super();
this._bufferSize = bufferSize < 1 ? 1 : bufferSize;
this._windowTime = windowTime < 1 ? 1 : windowTime;
}
next(value: T): void {
const now = this._getNow();
this._events.push(new ReplayEvent(now, value));
this._trimBufferThenGetEvents();
super.next(value);
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): Subscription {
const _events = this._trimBufferThenGetEvents();
const scheduler = this.scheduler;
let subscription: Subscription;
if (this.closed) {
throw new ObjectUnsubscribedError();
} else if (this.hasError) {
subscription = Subscription.EMPTY;
} else if (this.isStopped) {
subscription = Subscription.EMPTY;
} else {
this.observers.push(subscriber);
subscription = new SubjectSubscription(this, subscriber);
}
if (scheduler) {
subscriber.add(subscriber = new ObserveOnSubscriber<T>(subscriber, scheduler));
}
const len = _events.length;
for (let i = 0; i < len && !subscriber.closed; i++) {
subscriber.next(_events[i].value);
}
if (this.hasError) {
subscriber.error(this.thrownError);
} else if (this.isStopped) {
subscriber.complete();
}
return subscription;
}
_getNow(): number {
return (this.scheduler || queue).now();
}
private _trimBufferThenGetEvents(): ReplayEvent<T>[] {
const now = this._getNow();
const _bufferSize = this._bufferSize;
const _windowTime = this._windowTime;
const _events = this._events;
let eventsCount = _events.length;
let spliceCount = 0;
// Trim events that fall out of the time window.
// Start at the front of the list. Break early once
// we encounter an event that falls within the window.
while (spliceCount < eventsCount) {
if ((now - _events[spliceCount].time) < _windowTime) {
break;
}
spliceCount++;
}
if (eventsCount > _bufferSize) {
spliceCount = Math.max(spliceCount, eventsCount - _bufferSize);
}
if (spliceCount > 0) {
_events.splice(0, spliceCount);
}
return _events;
}
}
class ReplayEvent<T> {
constructor(public time: number, public value: T) {
}
}
+5
View File
@@ -0,0 +1,5 @@
(function (root, factory) {
root.Rx = factory();
})(window || global || this, function () {
return require('../dist/package/Rx');
});
+227
View File
@@ -0,0 +1,227 @@
/* tslint:disable:no-unused-variable */
// Subject imported before Observable to bypass circular dependency issue since
// Subject extends Observable and Observable references Subject in it's
// definition
export {Subject, AnonymousSubject} from './Subject';
/* tslint:enable:no-unused-variable */
export {Observable} from './Observable';
// statics
/* tslint:disable:no-use-before-declare */
import './add/observable/bindCallback';
import './add/observable/bindNodeCallback';
import './add/observable/combineLatest';
import './add/observable/concat';
import './add/observable/defer';
import './add/observable/empty';
import './add/observable/forkJoin';
import './add/observable/from';
import './add/observable/fromEvent';
import './add/observable/fromEventPattern';
import './add/observable/fromPromise';
import './add/observable/generate';
import './add/observable/if';
import './add/observable/interval';
import './add/observable/merge';
import './add/observable/race';
import './add/observable/never';
import './add/observable/of';
import './add/observable/onErrorResumeNext';
import './add/observable/pairs';
import './add/observable/range';
import './add/observable/using';
import './add/observable/throw';
import './add/observable/timer';
import './add/observable/zip';
//dom
import './add/observable/dom/ajax';
import './add/observable/dom/webSocket';
//operators
import './add/operator/buffer';
import './add/operator/bufferCount';
import './add/operator/bufferTime';
import './add/operator/bufferToggle';
import './add/operator/bufferWhen';
import './add/operator/catch';
import './add/operator/combineAll';
import './add/operator/combineLatest';
import './add/operator/concat';
import './add/operator/concatAll';
import './add/operator/concatMap';
import './add/operator/concatMapTo';
import './add/operator/count';
import './add/operator/dematerialize';
import './add/operator/debounce';
import './add/operator/debounceTime';
import './add/operator/defaultIfEmpty';
import './add/operator/delay';
import './add/operator/delayWhen';
import './add/operator/distinct';
import './add/operator/distinctUntilChanged';
import './add/operator/distinctUntilKeyChanged';
import './add/operator/do';
import './add/operator/exhaust';
import './add/operator/exhaustMap';
import './add/operator/expand';
import './add/operator/elementAt';
import './add/operator/filter';
import './add/operator/finally';
import './add/operator/find';
import './add/operator/findIndex';
import './add/operator/first';
import './add/operator/groupBy';
import './add/operator/ignoreElements';
import './add/operator/isEmpty';
import './add/operator/audit';
import './add/operator/auditTime';
import './add/operator/last';
import './add/operator/let';
import './add/operator/every';
import './add/operator/map';
import './add/operator/mapTo';
import './add/operator/materialize';
import './add/operator/max';
import './add/operator/merge';
import './add/operator/mergeAll';
import './add/operator/mergeMap';
import './add/operator/mergeMapTo';
import './add/operator/mergeScan';
import './add/operator/min';
import './add/operator/multicast';
import './add/operator/observeOn';
import './add/operator/onErrorResumeNext';
import './add/operator/pairwise';
import './add/operator/partition';
import './add/operator/pluck';
import './add/operator/publish';
import './add/operator/publishBehavior';
import './add/operator/publishReplay';
import './add/operator/publishLast';
import './add/operator/race';
import './add/operator/reduce';
import './add/operator/repeat';
import './add/operator/repeatWhen';
import './add/operator/retry';
import './add/operator/retryWhen';
import './add/operator/sample';
import './add/operator/sampleTime';
import './add/operator/scan';
import './add/operator/sequenceEqual';
import './add/operator/share';
import './add/operator/shareReplay';
import './add/operator/single';
import './add/operator/skip';
import './add/operator/skipLast';
import './add/operator/skipUntil';
import './add/operator/skipWhile';
import './add/operator/startWith';
import './add/operator/subscribeOn';
import './add/operator/switch';
import './add/operator/switchMap';
import './add/operator/switchMapTo';
import './add/operator/take';
import './add/operator/takeLast';
import './add/operator/takeUntil';
import './add/operator/takeWhile';
import './add/operator/throttle';
import './add/operator/throttleTime';
import './add/operator/timeInterval';
import './add/operator/timeout';
import './add/operator/timeoutWith';
import './add/operator/timestamp';
import './add/operator/toArray';
import './add/operator/toPromise';
import './add/operator/window';
import './add/operator/windowCount';
import './add/operator/windowTime';
import './add/operator/windowToggle';
import './add/operator/windowWhen';
import './add/operator/withLatestFrom';
import './add/operator/zip';
import './add/operator/zipAll';
/* tslint:disable:no-unused-variable */
export {Operator} from './Operator';
export {Observer} from './Observer';
export {Subscription} from './Subscription';
export {Subscriber} from './Subscriber';
export {AsyncSubject} from './AsyncSubject';
export {ReplaySubject} from './ReplaySubject';
export {BehaviorSubject} from './BehaviorSubject';
export {ConnectableObservable} from './observable/ConnectableObservable';
export {Notification} from './Notification';
export {EmptyError} from './util/EmptyError';
export {ArgumentOutOfRangeError} from './util/ArgumentOutOfRangeError';
export {ObjectUnsubscribedError} from './util/ObjectUnsubscribedError';
export {TimeoutError} from './util/TimeoutError';
export {UnsubscriptionError} from './util/UnsubscriptionError';
export {TimeInterval} from './operator/timeInterval';
export {Timestamp} from './operators/timestamp';
export {TestScheduler} from './testing/TestScheduler';
export {VirtualTimeScheduler} from './scheduler/VirtualTimeScheduler';
export {AjaxRequest, AjaxResponse, AjaxError, AjaxTimeoutError} from './observable/dom/AjaxObservable';
export { pipe } from './util/pipe';
import { asap } from './scheduler/asap';
import { async } from './scheduler/async';
import { queue } from './scheduler/queue';
import { animationFrame } from './scheduler/animationFrame';
import { AsapScheduler } from './scheduler/AsapScheduler';
import { AsyncScheduler } from './scheduler/AsyncScheduler';
import { QueueScheduler } from './scheduler/QueueScheduler';
import { AnimationFrameScheduler } from './scheduler/AnimationFrameScheduler';
import { rxSubscriber } from './symbol/rxSubscriber';
import { iterator } from './symbol/iterator';
import { observable } from './symbol/observable';
import * as _operators from './operators';
export const operators = _operators;
/* tslint:enable:no-unused-variable */
/**
* @typedef {Object} Rx.Scheduler
* @property {Scheduler} queue Schedules on a queue in the current event frame
* (trampoline scheduler). Use this for iteration operations.
* @property {Scheduler} asap Schedules on the micro task queue, which uses the
* fastest transport mechanism available, either Node.js' `process.nextTick()`
* or Web Worker MessageChannel or setTimeout or others. Use this for
* asynchronous conversions.
* @property {Scheduler} async Schedules work with `setInterval`. Use this for
* time-based operations.
* @property {Scheduler} animationFrame Schedules work with `requestAnimationFrame`.
* Use this for synchronizing with the platform's painting
*/
let Scheduler = {
asap,
queue,
animationFrame,
async
};
/**
* @typedef {Object} Rx.Symbol
* @property {Symbol|string} rxSubscriber A symbol to use as a property name to
* retrieve an "Rx safe" Observer from an object. "Rx safety" can be defined as
* an object that has all of the traits of an Rx Subscriber, including the
* ability to add and remove subscriptions to the subscription chain and
* guarantees involving event triggering (can't "next" after unsubscription,
* etc).
* @property {Symbol|string} observable A symbol to use as a property name to
* retrieve an Observable as defined by the [ECMAScript "Observable" spec](https://github.com/zenparsing/es-observable).
* @property {Symbol|string} iterator The ES6 symbol to use as a property name
* to retrieve an iterator from an object.
*/
let Symbol = {
rxSubscriber,
observable,
iterator
};
export {
Scheduler,
Symbol
};
+63
View File
@@ -0,0 +1,63 @@
import { Action } from './scheduler/Action';
import { Subscription } from './Subscription';
export interface IScheduler {
now(): number;
schedule<T>(work: (this: Action<T>, state?: T) => void, delay?: number, state?: T): Subscription;
}
/**
* An execution context and a data structure to order tasks and schedule their
* execution. Provides a notion of (potentially virtual) time, through the
* `now()` getter method.
*
* Each unit of work in a Scheduler is called an {@link Action}.
*
* ```ts
* class Scheduler {
* now(): number;
* schedule(work, delay?, state?): Subscription;
* }
* ```
*
* @class Scheduler
*/
export class Scheduler implements IScheduler {
public static now: () => number = Date.now ? Date.now : () => +new Date();
constructor(private SchedulerAction: typeof Action,
now: () => number = Scheduler.now) {
this.now = now;
}
/**
* A getter method that returns a number representing the current time
* (at the time this function was called) according to the scheduler's own
* internal clock.
* @return {number} A number that represents the current time. May or may not
* have a relation to wall-clock time. May or may not refer to a time unit
* (e.g. milliseconds).
*/
public now: () => number;
/**
* Schedules a function, `work`, for execution. May happen at some point in
* the future, according to the `delay` parameter, if specified. May be passed
* some context object, `state`, which will be passed to the `work` function.
*
* The given arguments will be processed an stored as an Action object in a
* queue of actions.
*
* @param {function(state: ?T): ?Subscription} work A function representing a
* task, or some unit of work to be executed by the Scheduler.
* @param {number} [delay] Time to wait before executing the work, where the
* time unit is implicit and defined by the Scheduler itself.
* @param {T} [state] Some contextual data that the `work` function uses when
* called by the Scheduler.
* @return {Subscription} A subscription in order to be able to unsubscribe
* the scheduled work.
*/
public schedule<T>(work: (this: Action<T>, state?: T) => void, delay: number = 0, state?: T): Subscription {
return new this.SchedulerAction<T>(this, work).schedule(state, delay);
}
}
+170
View File
@@ -0,0 +1,170 @@
import { Operator } from './Operator';
import { Observer } from './Observer';
import { Observable } from './Observable';
import { Subscriber } from './Subscriber';
import { ISubscription, Subscription, TeardownLogic } from './Subscription';
import { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';
import { SubjectSubscription } from './SubjectSubscription';
import { rxSubscriber as rxSubscriberSymbol } from './symbol/rxSubscriber';
/**
* @class SubjectSubscriber<T>
*/
export class SubjectSubscriber<T> extends Subscriber<T> {
constructor(protected destination: Subject<T>) {
super(destination);
}
}
/**
* @class Subject<T>
*/
export class Subject<T> extends Observable<T> implements ISubscription {
[rxSubscriberSymbol]() {
return new SubjectSubscriber(this);
}
observers: Observer<T>[] = [];
closed = false;
isStopped = false;
hasError = false;
thrownError: any = null;
constructor() {
super();
}
static create: Function = <T>(destination: Observer<T>, source: Observable<T>): AnonymousSubject<T> => {
return new AnonymousSubject<T>(destination, source);
}
lift<R>(operator: Operator<T, R>): Observable<R> {
const subject = new AnonymousSubject(this, this);
subject.operator = <any>operator;
return <any>subject;
}
next(value?: T) {
if (this.closed) {
throw new ObjectUnsubscribedError();
}
if (!this.isStopped) {
const { observers } = this;
const len = observers.length;
const copy = observers.slice();
for (let i = 0; i < len; i++) {
copy[i].next(value);
}
}
}
error(err: any) {
if (this.closed) {
throw new ObjectUnsubscribedError();
}
this.hasError = true;
this.thrownError = err;
this.isStopped = true;
const { observers } = this;
const len = observers.length;
const copy = observers.slice();
for (let i = 0; i < len; i++) {
copy[i].error(err);
}
this.observers.length = 0;
}
complete() {
if (this.closed) {
throw new ObjectUnsubscribedError();
}
this.isStopped = true;
const { observers } = this;
const len = observers.length;
const copy = observers.slice();
for (let i = 0; i < len; i++) {
copy[i].complete();
}
this.observers.length = 0;
}
unsubscribe() {
this.isStopped = true;
this.closed = true;
this.observers = null;
}
protected _trySubscribe(subscriber: Subscriber<T>): TeardownLogic {
if (this.closed) {
throw new ObjectUnsubscribedError();
} else {
return super._trySubscribe(subscriber);
}
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): Subscription {
if (this.closed) {
throw new ObjectUnsubscribedError();
} else if (this.hasError) {
subscriber.error(this.thrownError);
return Subscription.EMPTY;
} else if (this.isStopped) {
subscriber.complete();
return Subscription.EMPTY;
} else {
this.observers.push(subscriber);
return new SubjectSubscription(this, subscriber);
}
}
asObservable(): Observable<T> {
const observable = new Observable<T>();
(<any>observable).source = this;
return observable;
}
}
/**
* @class AnonymousSubject<T>
*/
export class AnonymousSubject<T> extends Subject<T> {
constructor(protected destination?: Observer<T>, source?: Observable<T>) {
super();
this.source = source;
}
next(value: T) {
const { destination } = this;
if (destination && destination.next) {
destination.next(value);
}
}
error(err: any) {
const { destination } = this;
if (destination && destination.error) {
this.destination.error(err);
}
}
complete() {
const { destination } = this;
if (destination && destination.complete) {
this.destination.complete();
}
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): Subscription {
const { source } = this;
if (source) {
return this.source.subscribe(subscriber);
} else {
return Subscription.EMPTY;
}
}
}
+39
View File
@@ -0,0 +1,39 @@
import { Subject } from './Subject';
import { Observer } from './Observer';
import { Subscription } from './Subscription';
/**
* We need this JSDoc comment for affecting ESDoc.
* @ignore
* @extends {Ignored}
*/
export class SubjectSubscription<T> extends Subscription {
closed: boolean = false;
constructor(public subject: Subject<T>, public subscriber: Observer<T>) {
super();
}
unsubscribe() {
if (this.closed) {
return;
}
this.closed = true;
const subject = this.subject;
const observers = subject.observers;
this.subject = null;
if (!observers || observers.length === 0 || subject.isStopped || subject.closed) {
return;
}
const subscriberIndex = observers.indexOf(this.subscriber);
if (subscriberIndex !== -1) {
observers.splice(subscriberIndex, 1);
}
}
}
+286
View File
@@ -0,0 +1,286 @@
import { isFunction } from './util/isFunction';
import { Observer, PartialObserver } from './Observer';
import { Subscription } from './Subscription';
import { empty as emptyObserver } from './Observer';
import { rxSubscriber as rxSubscriberSymbol } from './symbol/rxSubscriber';
/**
* Implements the {@link Observer} interface and extends the
* {@link Subscription} class. While the {@link Observer} is the public API for
* consuming the values of an {@link Observable}, all Observers get converted to
* a Subscriber, in order to provide Subscription-like capabilities such as
* `unsubscribe`. Subscriber is a common type in RxJS, and crucial for
* implementing operators, but it is rarely used as a public API.
*
* @class Subscriber<T>
*/
export class Subscriber<T> extends Subscription implements Observer<T> {
[rxSubscriberSymbol]() { return this; }
/**
* A static factory for a Subscriber, given a (potentially partial) definition
* of an Observer.
* @param {function(x: ?T): void} [next] The `next` callback of an Observer.
* @param {function(e: ?any): void} [error] The `error` callback of an
* Observer.
* @param {function(): void} [complete] The `complete` callback of an
* Observer.
* @return {Subscriber<T>} A Subscriber wrapping the (partially defined)
* Observer represented by the given arguments.
*/
static create<T>(next?: (x?: T) => void,
error?: (e?: any) => void,
complete?: () => void): Subscriber<T> {
const subscriber = new Subscriber(next, error, complete);
subscriber.syncErrorThrowable = false;
return subscriber;
}
public syncErrorValue: any = null;
public syncErrorThrown: boolean = false;
public syncErrorThrowable: boolean = false;
protected isStopped: boolean = false;
protected destination: PartialObserver<any>; // this `any` is the escape hatch to erase extra type param (e.g. R)
/**
* @param {Observer|function(value: T): void} [destinationOrNext] A partially
* defined Observer or a `next` callback function.
* @param {function(e: ?any): void} [error] The `error` callback of an
* Observer.
* @param {function(): void} [complete] The `complete` callback of an
* Observer.
*/
constructor(destinationOrNext?: PartialObserver<any> | ((value: T) => void),
error?: (e?: any) => void,
complete?: () => void) {
super();
switch (arguments.length) {
case 0:
this.destination = emptyObserver;
break;
case 1:
if (!destinationOrNext) {
this.destination = emptyObserver;
break;
}
if (typeof destinationOrNext === 'object') {
// HACK(benlesh): To resolve an issue where Node users may have multiple
// copies of rxjs in their node_modules directory.
if (isTrustedSubscriber(destinationOrNext)) {
const trustedSubscriber = destinationOrNext[rxSubscriberSymbol]() as Subscriber<any>;
this.syncErrorThrowable = trustedSubscriber.syncErrorThrowable;
this.destination = trustedSubscriber;
trustedSubscriber.add(this);
} else {
this.syncErrorThrowable = true;
this.destination = new SafeSubscriber<T>(this, <PartialObserver<any>> destinationOrNext);
}
break;
}
default:
this.syncErrorThrowable = true;
this.destination = new SafeSubscriber<T>(this, <((value: T) => void)> destinationOrNext, error, complete);
break;
}
}
/**
* The {@link Observer} callback to receive notifications of type `next` from
* the Observable, with a value. The Observable may call this method 0 or more
* times.
* @param {T} [value] The `next` value.
* @return {void}
*/
next(value?: T): void {
if (!this.isStopped) {
this._next(value);
}
}
/**
* The {@link Observer} callback to receive notifications of type `error` from
* the Observable, with an attached {@link Error}. Notifies the Observer that
* the Observable has experienced an error condition.
* @param {any} [err] The `error` exception.
* @return {void}
*/
error(err?: any): void {
if (!this.isStopped) {
this.isStopped = true;
this._error(err);
}
}
/**
* The {@link Observer} callback to receive a valueless notification of type
* `complete` from the Observable. Notifies the Observer that the Observable
* has finished sending push-based notifications.
* @return {void}
*/
complete(): void {
if (!this.isStopped) {
this.isStopped = true;
this._complete();
}
}
unsubscribe(): void {
if (this.closed) {
return;
}
this.isStopped = true;
super.unsubscribe();
}
protected _next(value: T): void {
this.destination.next(value);
}
protected _error(err: any): void {
this.destination.error(err);
this.unsubscribe();
}
protected _complete(): void {
this.destination.complete();
this.unsubscribe();
}
/** @deprecated internal use only */ _unsubscribeAndRecycle(): Subscriber<T> {
const { _parent, _parents } = this;
this._parent = null;
this._parents = null;
this.unsubscribe();
this.closed = false;
this.isStopped = false;
this._parent = _parent;
this._parents = _parents;
return this;
}
}
/**
* We need this JSDoc comment for affecting ESDoc.
* @ignore
* @extends {Ignored}
*/
class SafeSubscriber<T> extends Subscriber<T> {
private _context: any;
constructor(private _parentSubscriber: Subscriber<T>,
observerOrNext?: PartialObserver<T> | ((value: T) => void),
error?: (e?: any) => void,
complete?: () => void) {
super();
let next: ((value: T) => void);
let context: any = this;
if (isFunction(observerOrNext)) {
next = (<((value: T) => void)> observerOrNext);
} else if (observerOrNext) {
next = (<PartialObserver<T>> observerOrNext).next;
error = (<PartialObserver<T>> observerOrNext).error;
complete = (<PartialObserver<T>> observerOrNext).complete;
if (observerOrNext !== emptyObserver) {
context = Object.create(observerOrNext);
if (isFunction(context.unsubscribe)) {
this.add(<() => void> context.unsubscribe.bind(context));
}
context.unsubscribe = this.unsubscribe.bind(this);
}
}
this._context = context;
this._next = next;
this._error = error;
this._complete = complete;
}
next(value?: T): void {
if (!this.isStopped && this._next) {
const { _parentSubscriber } = this;
if (!_parentSubscriber.syncErrorThrowable) {
this.__tryOrUnsub(this._next, value);
} else if (this.__tryOrSetError(_parentSubscriber, this._next, value)) {
this.unsubscribe();
}
}
}
error(err?: any): void {
if (!this.isStopped) {
const { _parentSubscriber } = this;
if (this._error) {
if (!_parentSubscriber.syncErrorThrowable) {
this.__tryOrUnsub(this._error, err);
this.unsubscribe();
} else {
this.__tryOrSetError(_parentSubscriber, this._error, err);
this.unsubscribe();
}
} else if (!_parentSubscriber.syncErrorThrowable) {
this.unsubscribe();
throw err;
} else {
_parentSubscriber.syncErrorValue = err;
_parentSubscriber.syncErrorThrown = true;
this.unsubscribe();
}
}
}
complete(): void {
if (!this.isStopped) {
const { _parentSubscriber } = this;
if (this._complete) {
const wrappedComplete = () => this._complete.call(this._context);
if (!_parentSubscriber.syncErrorThrowable) {
this.__tryOrUnsub(wrappedComplete);
this.unsubscribe();
} else {
this.__tryOrSetError(_parentSubscriber, wrappedComplete);
this.unsubscribe();
}
} else {
this.unsubscribe();
}
}
}
private __tryOrUnsub(fn: Function, value?: any): void {
try {
fn.call(this._context, value);
} catch (err) {
this.unsubscribe();
throw err;
}
}
private __tryOrSetError(parent: Subscriber<T>, fn: Function, value?: any): boolean {
try {
fn.call(this._context, value);
} catch (err) {
parent.syncErrorValue = err;
parent.syncErrorThrown = true;
return true;
}
return false;
}
/** @deprecated internal use only */ _unsubscribe(): void {
const { _parentSubscriber } = this;
this._context = null;
this._parentSubscriber = null;
_parentSubscriber.unsubscribe();
}
}
function isTrustedSubscriber(obj: any) {
return obj instanceof Subscriber || ('syncErrorThrowable' in obj && obj[rxSubscriberSymbol]);
}
+222
View File
@@ -0,0 +1,222 @@
import { isArray } from './util/isArray';
import { isObject } from './util/isObject';
import { isFunction } from './util/isFunction';
import { tryCatch } from './util/tryCatch';
import { errorObject } from './util/errorObject';
import { UnsubscriptionError } from './util/UnsubscriptionError';
export interface AnonymousSubscription {
unsubscribe(): void;
}
export type TeardownLogic = AnonymousSubscription | Function | void;
export interface ISubscription extends AnonymousSubscription {
unsubscribe(): void;
readonly closed: boolean;
}
/**
* Represents a disposable resource, such as the execution of an Observable. A
* Subscription has one important method, `unsubscribe`, that takes no argument
* and just disposes the resource held by the subscription.
*
* Additionally, subscriptions may be grouped together through the `add()`
* method, which will attach a child Subscription to the current Subscription.
* When a Subscription is unsubscribed, all its children (and its grandchildren)
* will be unsubscribed as well.
*
* @class Subscription
*/
export class Subscription implements ISubscription {
public static EMPTY: Subscription = (function(empty: any){
empty.closed = true;
return empty;
}(new Subscription()));
/**
* A flag to indicate whether this Subscription has already been unsubscribed.
* @type {boolean}
*/
public closed: boolean = false;
protected _parent: Subscription = null;
protected _parents: Subscription[] = null;
private _subscriptions: ISubscription[] = null;
/**
* @param {function(): void} [unsubscribe] A function describing how to
* perform the disposal of resources when the `unsubscribe` method is called.
*/
constructor(unsubscribe?: () => void) {
if (unsubscribe) {
(<any> this)._unsubscribe = unsubscribe;
}
}
/**
* Disposes the resources held by the subscription. May, for instance, cancel
* an ongoing Observable execution or cancel any other type of work that
* started when the Subscription was created.
* @return {void}
*/
unsubscribe(): void {
let hasErrors = false;
let errors: any[];
if (this.closed) {
return;
}
let { _parent, _parents, _unsubscribe, _subscriptions } = (<any> this);
this.closed = true;
this._parent = null;
this._parents = null;
// null out _subscriptions first so any child subscriptions that attempt
// to remove themselves from this subscription will noop
this._subscriptions = null;
let index = -1;
let len = _parents ? _parents.length : 0;
// if this._parent is null, then so is this._parents, and we
// don't have to remove ourselves from any parent subscriptions.
while (_parent) {
_parent.remove(this);
// if this._parents is null or index >= len,
// then _parent is set to null, and the loop exits
_parent = ++index < len && _parents[index] || null;
}
if (isFunction(_unsubscribe)) {
let trial = tryCatch(_unsubscribe).call(this);
if (trial === errorObject) {
hasErrors = true;
errors = errors || (
errorObject.e instanceof UnsubscriptionError ?
flattenUnsubscriptionErrors(errorObject.e.errors) : [errorObject.e]
);
}
}
if (isArray(_subscriptions)) {
index = -1;
len = _subscriptions.length;
while (++index < len) {
const sub = _subscriptions[index];
if (isObject(sub)) {
let trial = tryCatch(sub.unsubscribe).call(sub);
if (trial === errorObject) {
hasErrors = true;
errors = errors || [];
let err = errorObject.e;
if (err instanceof UnsubscriptionError) {
errors = errors.concat(flattenUnsubscriptionErrors(err.errors));
} else {
errors.push(err);
}
}
}
}
}
if (hasErrors) {
throw new UnsubscriptionError(errors);
}
}
/**
* Adds a tear down to be called during the unsubscribe() of this
* Subscription.
*
* If the tear down being added is a subscription that is already
* unsubscribed, is the same reference `add` is being called on, or is
* `Subscription.EMPTY`, it will not be added.
*
* If this subscription is already in an `closed` state, the passed
* tear down logic will be executed immediately.
*
* @param {TeardownLogic} teardown The additional logic to execute on
* teardown.
* @return {Subscription} Returns the Subscription used or created to be
* added to the inner subscriptions list. This Subscription can be used with
* `remove()` to remove the passed teardown logic from the inner subscriptions
* list.
*/
add(teardown: TeardownLogic): Subscription {
if (!teardown || (teardown === Subscription.EMPTY)) {
return Subscription.EMPTY;
}
if (teardown === this) {
return this;
}
let subscription = (<Subscription> teardown);
switch (typeof teardown) {
case 'function':
subscription = new Subscription(<(() => void) > teardown);
case 'object':
if (subscription.closed || typeof subscription.unsubscribe !== 'function') {
return subscription;
} else if (this.closed) {
subscription.unsubscribe();
return subscription;
} else if (typeof subscription._addParent !== 'function' /* quack quack */) {
const tmp = subscription;
subscription = new Subscription();
subscription._subscriptions = [tmp];
}
break;
default:
throw new Error('unrecognized teardown ' + teardown + ' added to Subscription.');
}
const subscriptions = this._subscriptions || (this._subscriptions = []);
subscriptions.push(subscription);
subscription._addParent(this);
return subscription;
}
/**
* Removes a Subscription from the internal list of subscriptions that will
* unsubscribe during the unsubscribe process of this Subscription.
* @param {Subscription} subscription The subscription to remove.
* @return {void}
*/
remove(subscription: Subscription): void {
const subscriptions = this._subscriptions;
if (subscriptions) {
const subscriptionIndex = subscriptions.indexOf(subscription);
if (subscriptionIndex !== -1) {
subscriptions.splice(subscriptionIndex, 1);
}
}
}
private _addParent(parent: Subscription) {
let { _parent, _parents } = this;
if (!_parent || _parent === parent) {
// If we don't have a parent, or the new parent is the same as the
// current parent, then set this._parent to the new parent.
this._parent = parent;
} else if (!_parents) {
// If there's already one parent, but not multiple, allocate an Array to
// store the rest of the parent Subscriptions.
this._parents = [parent];
} else if (_parents.indexOf(parent) === -1) {
// Only add the new parent to the _parents list if it's not already there.
_parents.push(parent);
}
}
}
function flattenUnsubscriptionErrors(errors: any[]) {
return errors.reduce((errs, err) => errs.concat((err instanceof UnsubscriptionError) ? err.errors : err), []);
}
+1
View File
@@ -0,0 +1 @@
workspace(name = "rxjs")
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { bindCallback as staticBindCallback } from '../../observable/bindCallback';
Observable.bindCallback = staticBindCallback;
declare module '../../Observable' {
namespace Observable {
export let bindCallback: typeof staticBindCallback;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { bindNodeCallback as staticBindNodeCallback } from '../../observable/bindNodeCallback';
Observable.bindNodeCallback = staticBindNodeCallback;
declare module '../../Observable' {
namespace Observable {
export let bindNodeCallback: typeof staticBindNodeCallback;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { combineLatest as combineLatestStatic } from '../../observable/combineLatest';
Observable.combineLatest = combineLatestStatic;
declare module '../../Observable' {
namespace Observable {
export let combineLatest: typeof combineLatestStatic;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { concat as concatStatic } from '../../observable/concat';
Observable.concat = concatStatic;
declare module '../../Observable' {
namespace Observable {
export let concat: typeof concatStatic;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { defer as staticDefer } from '../../observable/defer';
Observable.defer = staticDefer;
declare module '../../Observable' {
namespace Observable {
export let defer: typeof staticDefer;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../../Observable';
import { ajax as staticAjax } from '../../../observable/dom/ajax';
import { AjaxCreationMethod } from '../../../observable/dom/AjaxObservable';
Observable.ajax = staticAjax;
declare module '../../../Observable' {
namespace Observable {
export let ajax: AjaxCreationMethod;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../../Observable';
import { webSocket as staticWebSocket } from '../../../observable/dom/webSocket';
Observable.webSocket = staticWebSocket;
declare module '../../../Observable' {
namespace Observable {
export let webSocket: typeof staticWebSocket;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { empty as staticEmpty } from '../../observable/empty';
Observable.empty = staticEmpty;
declare module '../../Observable' {
namespace Observable {
export let empty: typeof staticEmpty;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { forkJoin as staticForkJoin } from '../../observable/forkJoin';
Observable.forkJoin = staticForkJoin;
declare module '../../Observable' {
namespace Observable {
export let forkJoin: typeof staticForkJoin;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { from as staticFrom } from '../../observable/from';
Observable.from = staticFrom;
declare module '../../Observable' {
namespace Observable {
export let from: typeof staticFrom;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { fromEvent as staticFromEvent } from '../../observable/fromEvent';
Observable.fromEvent = staticFromEvent;
declare module '../../Observable' {
namespace Observable {
export let fromEvent: typeof staticFromEvent;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { fromEventPattern as staticFromEventPattern } from '../../observable/fromEventPattern';
Observable.fromEventPattern = staticFromEventPattern;
declare module '../../Observable' {
namespace Observable {
export let fromEventPattern: typeof staticFromEventPattern;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { fromPromise as staticFromPromise } from '../../observable/fromPromise';
Observable.fromPromise = staticFromPromise;
declare module '../../Observable' {
namespace Observable {
export let fromPromise: typeof staticFromPromise;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { generate as staticGenerate } from '../../observable/generate';
Observable.generate = staticGenerate;
declare module '../../Observable' {
namespace Observable {
export let generate: typeof staticGenerate;
}
}
+4
View File
@@ -0,0 +1,4 @@
import { Observable } from '../../Observable';
import { _if } from '../../observable/if';
Observable.if = _if;
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { interval as staticInterval } from '../../observable/interval';
Observable.interval = staticInterval;
declare module '../../Observable' {
namespace Observable {
export let interval: typeof staticInterval;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { merge as mergeStatic } from '../../observable/merge';
Observable.merge = mergeStatic;
declare module '../../Observable' {
namespace Observable {
export let merge: typeof mergeStatic;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { never as staticNever } from '../../observable/never';
Observable.never = staticNever;
declare module '../../Observable' {
namespace Observable {
export let never: typeof staticNever;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { of as staticOf } from '../../observable/of';
Observable.of = staticOf;
declare module '../../Observable' {
namespace Observable {
export let of: typeof staticOf; //formOf an iceberg!
}
}
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { onErrorResumeNext as staticOnErrorResumeNext } from '../../observable/onErrorResumeNext';
Observable.onErrorResumeNext = staticOnErrorResumeNext;
declare module '../../Observable' {
namespace Observable {
export let onErrorResumeNext: typeof staticOnErrorResumeNext;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { pairs as staticPairs } from '../../observable/pairs';
Observable.pairs = staticPairs;
declare module '../../Observable' {
namespace Observable {
export let pairs: typeof staticPairs;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { race as staticRace } from '../../observable/race';
Observable.race = staticRace;
declare module '../../Observable' {
namespace Observable {
export let race: typeof staticRace;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { range as staticRange } from '../../observable/range';
Observable.range = staticRange;
declare module '../../Observable' {
namespace Observable {
export let range: typeof staticRange;
}
}
+4
View File
@@ -0,0 +1,4 @@
import { Observable } from '../../Observable';
import { _throw } from '../../observable/throw';
Observable.throw = _throw;
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { timer as staticTimer } from '../../observable/timer';
Observable.timer = staticTimer;
declare module '../../Observable' {
namespace Observable {
export let timer: typeof staticTimer;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { using as staticUsing } from '../../observable/using';
Observable.using = staticUsing;
declare module '../../Observable' {
namespace Observable {
export let using: typeof staticUsing;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { zip as zipStatic } from '../../observable/zip';
Observable.zip = zipStatic;
declare module '../../Observable' {
namespace Observable {
export let zip: typeof zipStatic;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { audit } from '../../operator/audit';
Observable.prototype.audit = audit;
declare module '../../Observable' {
interface Observable<T> {
audit: typeof audit;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { auditTime } from '../../operator/auditTime';
Observable.prototype.auditTime = auditTime;
declare module '../../Observable' {
interface Observable<T> {
auditTime: typeof auditTime;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { buffer } from '../../operator/buffer';
Observable.prototype.buffer = buffer;
declare module '../../Observable' {
interface Observable<T> {
buffer: typeof buffer;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { bufferCount } from '../../operator/bufferCount';
Observable.prototype.bufferCount = bufferCount;
declare module '../../Observable' {
interface Observable<T> {
bufferCount: typeof bufferCount;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { bufferTime } from '../../operator/bufferTime';
Observable.prototype.bufferTime = bufferTime;
declare module '../../Observable' {
interface Observable<T> {
bufferTime: typeof bufferTime;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { bufferToggle } from '../../operator/bufferToggle';
Observable.prototype.bufferToggle = bufferToggle;
declare module '../../Observable' {
interface Observable<T> {
bufferToggle: typeof bufferToggle;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { bufferWhen } from '../../operator/bufferWhen';
Observable.prototype.bufferWhen = bufferWhen;
declare module '../../Observable' {
interface Observable<T> {
bufferWhen: typeof bufferWhen;
}
}
+13
View File
@@ -0,0 +1,13 @@
import { Observable } from '../../Observable';
import { _catch } from '../../operator/catch';
Observable.prototype.catch = _catch;
Observable.prototype._catch = _catch;
declare module '../../Observable' {
interface Observable<T> {
catch: typeof _catch;
_catch: typeof _catch;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { combineAll } from '../../operator/combineAll';
Observable.prototype.combineAll = combineAll;
declare module '../../Observable' {
interface Observable<T> {
combineAll: typeof combineAll;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { combineLatest } from '../../operator/combineLatest';
Observable.prototype.combineLatest = combineLatest;
declare module '../../Observable' {
interface Observable<T> {
combineLatest: typeof combineLatest;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { concat } from '../../operator/concat';
Observable.prototype.concat = concat;
declare module '../../Observable' {
interface Observable<T> {
concat: typeof concat;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { concatAll } from '../../operator/concatAll';
Observable.prototype.concatAll = concatAll;
declare module '../../Observable' {
interface Observable<T> {
concatAll: typeof concatAll;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { concatMap } from '../../operator/concatMap';
Observable.prototype.concatMap = concatMap;
declare module '../../Observable' {
interface Observable<T> {
concatMap: typeof concatMap;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { concatMapTo } from '../../operator/concatMapTo';
Observable.prototype.concatMapTo = concatMapTo;
declare module '../../Observable' {
interface Observable<T> {
concatMapTo: typeof concatMapTo;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { count } from '../../operator/count';
Observable.prototype.count = count;
declare module '../../Observable' {
interface Observable<T> {
count: typeof count;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { debounce } from '../../operator/debounce';
Observable.prototype.debounce = debounce;
declare module '../../Observable' {
interface Observable<T> {
debounce: typeof debounce;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { debounceTime } from '../../operator/debounceTime';
Observable.prototype.debounceTime = debounceTime;
declare module '../../Observable' {
interface Observable<T> {
debounceTime: typeof debounceTime;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { defaultIfEmpty } from '../../operator/defaultIfEmpty';
Observable.prototype.defaultIfEmpty = defaultIfEmpty;
declare module '../../Observable' {
interface Observable<T> {
defaultIfEmpty: typeof defaultIfEmpty;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { delay } from '../../operator/delay';
Observable.prototype.delay = delay;
declare module '../../Observable' {
interface Observable<T> {
delay: typeof delay;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { delayWhen } from '../../operator/delayWhen';
Observable.prototype.delayWhen = delayWhen;
declare module '../../Observable' {
interface Observable<T> {
delayWhen: typeof delayWhen;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { dematerialize } from '../../operator/dematerialize';
Observable.prototype.dematerialize = dematerialize;
declare module '../../Observable' {
interface Observable<T> {
dematerialize: typeof dematerialize;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { distinct } from '../../operator/distinct';
Observable.prototype.distinct = distinct;
declare module '../../Observable' {
interface Observable<T> {
distinct: typeof distinct;
}
}
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { distinctUntilChanged } from '../../operator/distinctUntilChanged';
Observable.prototype.distinctUntilChanged = distinctUntilChanged;
declare module '../../Observable' {
interface Observable<T> {
distinctUntilChanged: typeof distinctUntilChanged;
}
}
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { distinctUntilKeyChanged } from '../../operator/distinctUntilKeyChanged';
Observable.prototype.distinctUntilKeyChanged = distinctUntilKeyChanged;
declare module '../../Observable' {
interface Observable<T> {
distinctUntilKeyChanged: typeof distinctUntilKeyChanged;
}
}
+13
View File
@@ -0,0 +1,13 @@
import { Observable } from '../../Observable';
import { _do } from '../../operator/do';
Observable.prototype.do = _do;
Observable.prototype._do = _do;
declare module '../../Observable' {
interface Observable<T> {
do: typeof _do;
_do: typeof _do;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { elementAt } from '../../operator/elementAt';
Observable.prototype.elementAt = elementAt;
declare module '../../Observable' {
interface Observable<T> {
elementAt: typeof elementAt;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { every } from '../../operator/every';
Observable.prototype.every = every;
declare module '../../Observable' {
interface Observable<T> {
every: typeof every;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { exhaust } from '../../operator/exhaust';
Observable.prototype.exhaust = exhaust;
declare module '../../Observable' {
interface Observable<T> {
exhaust: typeof exhaust;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { exhaustMap } from '../../operator/exhaustMap';
Observable.prototype.exhaustMap = exhaustMap;
declare module '../../Observable' {
interface Observable<T> {
exhaustMap: typeof exhaustMap;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { expand } from '../../operator/expand';
Observable.prototype.expand = expand;
declare module '../../Observable' {
interface Observable<T> {
expand: typeof expand;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { filter } from '../../operator/filter';
Observable.prototype.filter = filter;
declare module '../../Observable' {
interface Observable<T> {
filter: typeof filter;
}
}
+13
View File
@@ -0,0 +1,13 @@
import { Observable } from '../../Observable';
import { _finally } from '../../operator/finally';
Observable.prototype.finally = _finally;
Observable.prototype._finally = _finally;
declare module '../../Observable' {
interface Observable<T> {
finally: typeof _finally;
_finally: typeof _finally;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { find } from '../../operator/find';
Observable.prototype.find = find;
declare module '../../Observable' {
interface Observable<T> {
find: typeof find;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { findIndex } from '../../operator/findIndex';
Observable.prototype.findIndex = findIndex;
declare module '../../Observable' {
interface Observable<T> {
findIndex: typeof findIndex;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { first } from '../../operator/first';
Observable.prototype.first = <any>first;
declare module '../../Observable' {
interface Observable<T> {
first: typeof first;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { groupBy } from '../../operator/groupBy';
Observable.prototype.groupBy = <any>groupBy;
declare module '../../Observable' {
interface Observable<T> {
groupBy: typeof groupBy;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { ignoreElements } from '../../operator/ignoreElements';
Observable.prototype.ignoreElements = ignoreElements;
declare module '../../Observable' {
interface Observable<T> {
ignoreElements: typeof ignoreElements;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { isEmpty } from '../../operator/isEmpty';
Observable.prototype.isEmpty = isEmpty;
declare module '../../Observable' {
interface Observable<T> {
isEmpty: typeof isEmpty;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { last } from '../../operator/last';
Observable.prototype.last = <any>last;
declare module '../../Observable' {
interface Observable<T> {
last: typeof last;
}
}
+13
View File
@@ -0,0 +1,13 @@
import { Observable } from '../../Observable';
import { letProto } from '../../operator/let';
Observable.prototype.let = letProto;
Observable.prototype.letBind = letProto;
declare module '../../Observable' {
interface Observable<T> {
let: typeof letProto;
letBind: typeof letProto;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { map } from '../../operator/map';
Observable.prototype.map = map;
declare module '../../Observable' {
interface Observable<T> {
map: typeof map;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { mapTo } from '../../operator/mapTo';
Observable.prototype.mapTo = mapTo;
declare module '../../Observable' {
interface Observable<T> {
mapTo: typeof mapTo;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { materialize } from '../../operator/materialize';
Observable.prototype.materialize = materialize;
declare module '../../Observable' {
interface Observable<T> {
materialize: typeof materialize;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { max } from '../../operator/max';
Observable.prototype.max = max;
declare module '../../Observable' {
interface Observable<T> {
max: typeof max;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { merge } from '../../operator/merge';
Observable.prototype.merge = merge;
declare module '../../Observable' {
interface Observable<T> {
merge: typeof merge;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { mergeAll } from '../../operator/mergeAll';
Observable.prototype.mergeAll = mergeAll;
declare module '../../Observable' {
interface Observable<T> {
mergeAll: typeof mergeAll;
}
}
+13
View File
@@ -0,0 +1,13 @@
import { Observable } from '../../Observable';
import { mergeMap } from '../../operator/mergeMap';
Observable.prototype.mergeMap = <any>mergeMap;
Observable.prototype.flatMap = <any>mergeMap;
declare module '../../Observable' {
interface Observable<T> {
flatMap: typeof mergeMap;
mergeMap: typeof mergeMap;
}
}
+13
View File
@@ -0,0 +1,13 @@
import { Observable } from '../../Observable';
import { mergeMapTo } from '../../operator/mergeMapTo';
Observable.prototype.flatMapTo = <any>mergeMapTo;
Observable.prototype.mergeMapTo = <any>mergeMapTo;
declare module '../../Observable' {
interface Observable<T> {
flatMapTo: typeof mergeMapTo;
mergeMapTo: typeof mergeMapTo;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { mergeScan } from '../../operator/mergeScan';
Observable.prototype.mergeScan = mergeScan;
declare module '../../Observable' {
interface Observable<T> {
mergeScan: typeof mergeScan;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { min } from '../../operator/min';
Observable.prototype.min = min;
declare module '../../Observable' {
interface Observable<T> {
min: typeof min;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { multicast } from '../../operator/multicast';
Observable.prototype.multicast = <any>multicast;
declare module '../../Observable' {
interface Observable<T> {
multicast: typeof multicast;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { observeOn } from '../../operator/observeOn';
Observable.prototype.observeOn = observeOn;
declare module '../../Observable' {
interface Observable<T> {
observeOn: typeof observeOn;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { onErrorResumeNext } from '../../operator/onErrorResumeNext';
Observable.prototype.onErrorResumeNext = onErrorResumeNext;
declare module '../../Observable' {
interface Observable<T> {
onErrorResumeNext: typeof onErrorResumeNext;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { pairwise } from '../../operator/pairwise';
Observable.prototype.pairwise = pairwise;
declare module '../../Observable' {
interface Observable<T> {
pairwise: typeof pairwise;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { partition } from '../../operator/partition';
Observable.prototype.partition = partition;
declare module '../../Observable' {
interface Observable<T> {
partition: typeof partition;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { pluck } from '../../operator/pluck';
Observable.prototype.pluck = pluck;
declare module '../../Observable' {
interface Observable<T> {
pluck: typeof pluck;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { publish } from '../../operator/publish';
Observable.prototype.publish = <any>publish;
declare module '../../Observable' {
interface Observable<T> {
publish: typeof publish;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { publishBehavior } from '../../operator/publishBehavior';
Observable.prototype.publishBehavior = publishBehavior;
declare module '../../Observable' {
interface Observable<T> {
publishBehavior: typeof publishBehavior;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { publishLast } from '../../operator/publishLast';
Observable.prototype.publishLast = publishLast;
declare module '../../Observable' {
interface Observable<T> {
publishLast: typeof publishLast;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { publishReplay } from '../../operator/publishReplay';
Observable.prototype.publishReplay = publishReplay;
declare module '../../Observable' {
interface Observable<T> {
publishReplay: typeof publishReplay;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { race } from '../../operator/race';
Observable.prototype.race = race;
declare module '../../Observable' {
interface Observable<T> {
race: typeof race;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { reduce } from '../../operator/reduce';
Observable.prototype.reduce = reduce;
declare module '../../Observable' {
interface Observable<T> {
reduce: typeof reduce;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { repeat } from '../../operator/repeat';
Observable.prototype.repeat = repeat;
declare module '../../Observable' {
interface Observable<T> {
repeat: typeof repeat;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { repeatWhen } from '../../operator/repeatWhen';
Observable.prototype.repeatWhen = repeatWhen;
declare module '../../Observable' {
interface Observable<T> {
repeatWhen: typeof repeatWhen;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { retry } from '../../operator/retry';
Observable.prototype.retry = retry;
declare module '../../Observable' {
interface Observable<T> {
retry: typeof retry;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { retryWhen } from '../../operator/retryWhen';
Observable.prototype.retryWhen = retryWhen;
declare module '../../Observable' {
interface Observable<T> {
retryWhen: typeof retryWhen;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { sample } from '../../operator/sample';
Observable.prototype.sample = sample;
declare module '../../Observable' {
interface Observable<T> {
sample: typeof sample;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { sampleTime } from '../../operator/sampleTime';
Observable.prototype.sampleTime = sampleTime;
declare module '../../Observable' {
interface Observable<T> {
sampleTime: typeof sampleTime;
}
}
+12
View File
@@ -0,0 +1,12 @@
import { Observable } from '../../Observable';
import { scan } from '../../operator/scan';
Observable.prototype.scan = scan;
declare module '../../Observable' {
interface Observable<T> {
scan: typeof scan;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { sequenceEqual } from '../../operator/sequenceEqual';
Observable.prototype.sequenceEqual = sequenceEqual;
declare module '../../Observable' {
interface Observable<T> {
sequenceEqual: typeof sequenceEqual;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { share } from '../../operator/share';
Observable.prototype.share = share;
declare module '../../Observable' {
interface Observable<T> {
share: typeof share;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { shareReplay } from '../../operator/shareReplay';
Observable.prototype.shareReplay = shareReplay;
declare module '../../Observable' {
interface Observable<T> {
shareReplay: typeof shareReplay;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { single } from '../../operator/single';
Observable.prototype.single = single;
declare module '../../Observable' {
interface Observable<T> {
single: typeof single;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { skip } from '../../operator/skip';
Observable.prototype.skip = skip;
declare module '../../Observable' {
interface Observable<T> {
skip: typeof skip;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { skipLast } from '../../operator/skipLast';
Observable.prototype.skipLast = skipLast;
declare module '../../Observable' {
interface Observable<T> {
skipLast: typeof skipLast;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { skipUntil } from '../../operator/skipUntil';
Observable.prototype.skipUntil = skipUntil;
declare module '../../Observable' {
interface Observable<T> {
skipUntil: typeof skipUntil;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { skipWhile } from '../../operator/skipWhile';
Observable.prototype.skipWhile = skipWhile;
declare module '../../Observable' {
interface Observable<T> {
skipWhile: typeof skipWhile;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { startWith } from '../../operator/startWith';
Observable.prototype.startWith = startWith;
declare module '../../Observable' {
interface Observable<T> {
startWith: typeof startWith;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { subscribeOn } from '../../operator/subscribeOn';
Observable.prototype.subscribeOn = subscribeOn;
declare module '../../Observable' {
interface Observable<T> {
subscribeOn: typeof subscribeOn;
}
}
+13
View File
@@ -0,0 +1,13 @@
import { Observable } from '../../Observable';
import { _switch } from '../../operator/switch';
Observable.prototype.switch = _switch;
Observable.prototype._switch = _switch;
declare module '../../Observable' {
interface Observable<T> {
switch: typeof _switch;
_switch: typeof _switch;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { switchMap } from '../../operator/switchMap';
Observable.prototype.switchMap = switchMap;
declare module '../../Observable' {
interface Observable<T> {
switchMap: typeof switchMap;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { switchMapTo } from '../../operator/switchMapTo';
Observable.prototype.switchMapTo = switchMapTo;
declare module '../../Observable' {
interface Observable<T> {
switchMapTo: typeof switchMapTo;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { take } from '../../operator/take';
Observable.prototype.take = take;
declare module '../../Observable' {
interface Observable<T> {
take: typeof take;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { takeLast } from '../../operator/takeLast';
Observable.prototype.takeLast = takeLast;
declare module '../../Observable' {
interface Observable<T> {
takeLast: typeof takeLast;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { takeUntil } from '../../operator/takeUntil';
Observable.prototype.takeUntil = takeUntil;
declare module '../../Observable' {
interface Observable<T> {
takeUntil: typeof takeUntil;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { takeWhile } from '../../operator/takeWhile';
Observable.prototype.takeWhile = takeWhile;
declare module '../../Observable' {
interface Observable<T> {
takeWhile: typeof takeWhile;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { throttle } from '../../operator/throttle';
Observable.prototype.throttle = throttle;
declare module '../../Observable' {
interface Observable<T> {
throttle: typeof throttle;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { throttleTime } from '../../operator/throttleTime';
Observable.prototype.throttleTime = throttleTime;
declare module '../../Observable' {
interface Observable<T> {
throttleTime: typeof throttleTime;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { timeInterval } from '../../operator/timeInterval';
Observable.prototype.timeInterval = timeInterval;
declare module '../../Observable' {
interface Observable<T> {
timeInterval: typeof timeInterval;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { timeout } from '../../operator/timeout';
Observable.prototype.timeout = timeout;
declare module '../../Observable' {
interface Observable<T> {
timeout: typeof timeout;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { timeoutWith } from '../../operator/timeoutWith';
Observable.prototype.timeoutWith = timeoutWith;
declare module '../../Observable' {
interface Observable<T> {
timeoutWith: typeof timeoutWith;
}
}
+10
View File
@@ -0,0 +1,10 @@
import { Observable } from '../../Observable';
import { timestamp } from '../../operator/timestamp';
Observable.prototype.timestamp = timestamp;
declare module '../../Observable' {
interface Observable<T> {
timestamp: typeof timestamp;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { toArray } from '../../operator/toArray';
Observable.prototype.toArray = toArray;
declare module '../../Observable' {
interface Observable<T> {
toArray: typeof toArray;
}
}
+2
View File
@@ -0,0 +1,2 @@
// HACK: does nothing, because `toPromise` now lives on the `Observable` itself.
// leaving this module here to prevent breakage.
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { window } from '../../operator/window';
Observable.prototype.window = window;
declare module '../../Observable' {
interface Observable<T> {
window: typeof window;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { windowCount } from '../../operator/windowCount';
Observable.prototype.windowCount = windowCount;
declare module '../../Observable' {
interface Observable<T> {
windowCount: typeof windowCount;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { windowTime } from '../../operator/windowTime';
Observable.prototype.windowTime = windowTime;
declare module '../../Observable' {
interface Observable<T> {
windowTime: typeof windowTime;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { windowToggle } from '../../operator/windowToggle';
Observable.prototype.windowToggle = windowToggle;
declare module '../../Observable' {
interface Observable<T> {
windowToggle: typeof windowToggle;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { windowWhen } from '../../operator/windowWhen';
Observable.prototype.windowWhen = windowWhen;
declare module '../../Observable' {
interface Observable<T> {
windowWhen: typeof windowWhen;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { withLatestFrom } from '../../operator/withLatestFrom';
Observable.prototype.withLatestFrom = withLatestFrom;
declare module '../../Observable' {
interface Observable<T> {
withLatestFrom: typeof withLatestFrom;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { zipProto } from '../../operator/zip';
Observable.prototype.zip = zipProto;
declare module '../../Observable' {
interface Observable<T> {
zip: typeof zipProto;
}
}
+11
View File
@@ -0,0 +1,11 @@
import { Observable } from '../../Observable';
import { zipAll } from '../../operator/zipAll';
Observable.prototype.zipAll = zipAll;
declare module '../../Observable' {
interface Observable<T> {
zipAll: typeof zipAll;
}
}
+9
View File
@@ -0,0 +1,9 @@
import { Observable } from './Observable';
export type UnaryFunction<T, R> = (source: T) => R;
export type OperatorFunction<T, R> = UnaryFunction<Observable<T>, Observable<R>>;
export type FactoryOrValue<T> = T | (() => T);
export type MonoTypeOperatorFunction<T> = OperatorFunction<T, T>;
+72
View File
@@ -0,0 +1,72 @@
import { IScheduler } from '../Scheduler';
import { Observable } from '../Observable';
import { ScalarObservable } from './ScalarObservable';
import { EmptyObservable } from './EmptyObservable';
import { Subscriber } from '../Subscriber';
import { TeardownLogic } from '../Subscription';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class ArrayLikeObservable<T> extends Observable<T> {
static create<T>(arrayLike: ArrayLike<T>, scheduler?: IScheduler): Observable<T> {
const length = arrayLike.length;
if (length === 0) {
return new EmptyObservable<T>();
} else if (length === 1) {
return new ScalarObservable<T>(<any>arrayLike[0], scheduler);
} else {
return new ArrayLikeObservable(arrayLike, scheduler);
}
}
static dispatch(state: any) {
const { arrayLike, index, length, subscriber } = state;
if (subscriber.closed) {
return;
}
if (index >= length) {
subscriber.complete();
return;
}
subscriber.next(arrayLike[index]);
state.index = index + 1;
(<any> this).schedule(state);
}
// value used if Array has one value and _isScalar
private value: any;
constructor(private arrayLike: ArrayLike<T>, private scheduler?: IScheduler) {
super();
if (!scheduler && arrayLike.length === 1) {
this._isScalar = true;
this.value = arrayLike[0];
}
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): TeardownLogic {
let index = 0;
const { arrayLike, scheduler } = this;
const length = arrayLike.length;
if (scheduler) {
return scheduler.schedule(ArrayLikeObservable.dispatch, 0, {
arrayLike, index, length, subscriber
});
} else {
for (let i = 0; i < length && !subscriber.closed; i++) {
subscriber.next(arrayLike[i]);
}
subscriber.complete();
}
}
}
+129
View File
@@ -0,0 +1,129 @@
import { IScheduler } from '../Scheduler';
import { Observable } from '../Observable';
import { ScalarObservable } from './ScalarObservable';
import { EmptyObservable } from './EmptyObservable';
import { Subscriber } from '../Subscriber';
import { isScheduler } from '../util/isScheduler';
import { TeardownLogic } from '../Subscription';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class ArrayObservable<T> extends Observable<T> {
static create<T>(array: T[], scheduler?: IScheduler): Observable<T> {
return new ArrayObservable(array, scheduler);
}
static of<T>(item1: T, scheduler?: IScheduler): Observable<T>;
static of<T>(item1: T, item2: T, scheduler?: IScheduler): Observable<T>;
static of<T>(item1: T, item2: T, item3: T, scheduler?: IScheduler): Observable<T>;
static of<T>(item1: T, item2: T, item3: T, item4: T, scheduler?: IScheduler): Observable<T>;
static of<T>(item1: T, item2: T, item3: T, item4: T, item5: T, scheduler?: IScheduler): Observable<T>;
static of<T>(item1: T, item2: T, item3: T, item4: T, item5: T, item6: T, scheduler?: IScheduler): Observable<T>;
static of<T>(...array: Array<T | IScheduler>): Observable<T>;
/**
* Creates an Observable that emits some values you specify as arguments,
* immediately one after the other, and then emits a complete notification.
*
* <span class="informal">Emits the arguments you provide, then completes.
* </span>
*
* <img src="./img/of.png" width="100%">
*
* This static operator is useful for creating a simple Observable that only
* emits the arguments given, and the complete notification thereafter. It can
* be used for composing with other Observables, such as with {@link concat}.
* By default, it uses a `null` IScheduler, which means the `next`
* notifications are sent synchronously, although with a different IScheduler
* it is possible to determine when those notifications will be delivered.
*
* @example <caption>Emit 10, 20, 30, then 'a', 'b', 'c', then start ticking every second.</caption>
* var numbers = Rx.Observable.of(10, 20, 30);
* var letters = Rx.Observable.of('a', 'b', 'c');
* var interval = Rx.Observable.interval(1000);
* var result = numbers.concat(letters).concat(interval);
* result.subscribe(x => console.log(x));
*
* @see {@link create}
* @see {@link empty}
* @see {@link never}
* @see {@link throw}
*
* @param {...T} values Arguments that represent `next` values to be emitted.
* @param {Scheduler} [scheduler] A {@link IScheduler} to use for scheduling
* the emissions of the `next` notifications.
* @return {Observable<T>} An Observable that emits each given input value.
* @static true
* @name of
* @owner Observable
*/
static of<T>(...array: Array<T | IScheduler>): Observable<T> {
let scheduler = <IScheduler>array[array.length - 1];
if (isScheduler(scheduler)) {
array.pop();
} else {
scheduler = null;
}
const len = array.length;
if (len > 1) {
return new ArrayObservable<T>(<any>array, scheduler);
} else if (len === 1) {
return new ScalarObservable<T>(<any>array[0], scheduler);
} else {
return new EmptyObservable<T>(scheduler);
}
}
static dispatch(state: any) {
const { array, index, count, subscriber } = state;
if (index >= count) {
subscriber.complete();
return;
}
subscriber.next(array[index]);
if (subscriber.closed) {
return;
}
state.index = index + 1;
(<any> this).schedule(state);
}
// value used if Array has one value and _isScalar
value: any;
constructor(private array: T[], private scheduler?: IScheduler) {
super();
if (!scheduler && array.length === 1) {
this._isScalar = true;
this.value = array[0];
}
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): TeardownLogic {
let index = 0;
const array = this.array;
const count = array.length;
const scheduler = this.scheduler;
if (scheduler) {
return scheduler.schedule(ArrayObservable.dispatch, 0, {
array, index, count, subscriber
});
} else {
for (let i = 0; i < count && !subscriber.closed; i++) {
subscriber.next(array[i]);
}
subscriber.complete();
}
}
}
@@ -0,0 +1,281 @@
import { Observable } from '../Observable';
import { Subscriber } from '../Subscriber';
import { Subscription } from '../Subscription';
import { IScheduler } from '../Scheduler';
import { tryCatch } from '../util/tryCatch';
import { errorObject } from '../util/errorObject';
import { AsyncSubject } from '../AsyncSubject';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class BoundCallbackObservable<T> extends Observable<T> {
subject: AsyncSubject<T>;
/* tslint:disable:max-line-length */
static create(callbackFunc: (callback: () => any) => any, selector?: void, scheduler?: IScheduler): () => Observable<void>;
static create<R>(callbackFunc: (callback: (result: R) => any) => any, selector?: void, scheduler?: IScheduler): () => Observable<R>;
static create<T, R>(callbackFunc: (v1: T, callback: (result: R) => any) => any, selector?: void, scheduler?: IScheduler): (v1: T) => Observable<R>;
static create<T, T2, R>(callbackFunc: (v1: T, v2: T2, callback: (result: R) => any) => any, selector?: void, scheduler?: IScheduler): (v1: T, v2: T2) => Observable<R>;
static create<T, T2, T3, R>(callbackFunc: (v1: T, v2: T2, v3: T3, callback: (result: R) => any) => any, selector?: void, scheduler?: IScheduler): (v1: T, v2: T2, v3: T3) => Observable<R>;
static create<T, T2, T3, T4, R>(callbackFunc: (v1: T, v2: T2, v3: T3, v4: T4, callback: (result: R) => any) => any, selector?: void, scheduler?: IScheduler): (v1: T, v2: T2, v3: T3, v4: T4) => Observable<R>;
static create<T, T2, T3, T4, T5, R>(callbackFunc: (v1: T, v2: T2, v3: T3, v4: T4, v5: T5, callback: (result: R) => any) => any, selector?: void, scheduler?: IScheduler): (v1: T, v2: T2, v3: T3, v4: T4, v5: T5) => Observable<R>;
static create<T, T2, T3, T4, T5, T6, R>(callbackFunc: (v1: T, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6, callback: (result: R) => any) => any, selector?: void, scheduler?: IScheduler): (v1: T, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6) => Observable<R>;
static create<R>(callbackFunc: (callback: (...args: any[]) => any) => any, selector: (...args: any[]) => R, scheduler?: IScheduler): () => Observable<R>;
static create<T, R>(callbackFunc: (v1: T, callback: (...args: any[]) => any) => any, selector: (...args: any[]) => R, scheduler?: IScheduler): (v1: T) => Observable<R>;
static create<T, T2, R>(callbackFunc: (v1: T, v2: T2, callback: (...args: any[]) => any) => any, selector: (...args: any[]) => R, scheduler?: IScheduler): (v1: T, v2: T2) => Observable<R>;
static create<T, T2, T3, R>(callbackFunc: (v1: T, v2: T2, v3: T3, callback: (...args: any[]) => any) => any, selector: (...args: any[]) => R, scheduler?: IScheduler): (v1: T, v2: T2, v3: T3) => Observable<R>;
static create<T, T2, T3, T4, R>(callbackFunc: (v1: T, v2: T2, v3: T3, v4: T4, callback: (...args: any[]) => any) => any, selector: (...args: any[]) => R, scheduler?: IScheduler): (v1: T, v2: T2, v3: T3, v4: T4) => Observable<R>;
static create<T, T2, T3, T4, T5, R>(callbackFunc: (v1: T, v2: T2, v3: T3, v4: T4, v5: T5, callback: (...args: any[]) => any) => any, selector: (...args: any[]) => R, scheduler?: IScheduler): (v1: T, v2: T2, v3: T3, v4: T4, v5: T5) => Observable<R>;
static create<T, T2, T3, T4, T5, T6, R>(callbackFunc: (v1: T, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6, callback: (...args: any[]) => any) => any, selector: (...args: any[]) => R, scheduler?: IScheduler): (v1: T, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6) => Observable<R>;
static create<T>(callbackFunc: Function, selector?: void, scheduler?: IScheduler): (...args: any[]) => Observable<T>;
static create<T>(callbackFunc: Function, selector?: (...args: any[]) => T, scheduler?: IScheduler): (...args: any[]) => Observable<T>;
/* tslint:enable:max-line-length */
/**
* Converts a callback API to a function that returns an Observable.
*
* <span class="informal">Give it a function `f` of type `f(x, callback)` and
* it will return a function `g` that when called as `g(x)` will output an
* Observable.</span>
*
* `bindCallback` is not an operator because its input and output are not
* Observables. The input is a function `func` with some parameters, the
* last parameter must be a callback function that `func` calls when it is
* done.
*
* The output of `bindCallback` is a function that takes the same parameters
* as `func`, except the last one (the callback). When the output function
* is called with arguments it will return an Observable. If function `func`
* calls its callback with one argument the Observable will emit that value.
* If on the other hand the callback is called with multiple values the resulting
* Observable will emit an array with said values as arguments.
*
* It is very important to remember that input function `func` is not called
* when the output function is, but rather when the Observable returned by the output
* function is subscribed. This means if `func` makes an AJAX request, that request
* will be made every time someone subscribes to the resulting Observable, but not before.
*
* Optionally, a selector function can be passed to `bindObservable`. The selector function
* takes the same arguments as the callback and returns the value that will be emitted by the Observable.
* Even though by default multiple arguments passed to callback appear in the stream as an array
* the selector function will be called with arguments directly, just as the callback would.
* This means you can imagine the default selector (when one is not provided explicitly)
* as a function that aggregates all its arguments into an array, or simply returns first argument
* if there is only one.
*
* The last optional parameter - {@link Scheduler} - can be used to control when the call
* to `func` happens after someone subscribes to Observable, as well as when results
* passed to callback will be emitted. By default, the subscription to an Observable calls `func`
* synchronously, but using `Scheduler.async` as the last parameter will defer the call to `func`,
* just like wrapping the call in `setTimeout` with a timeout of `0` would. If you use the async Scheduler
* and call `subscribe` on the output Observable all function calls that are currently executing
* will end before `func` is invoked.
*
* By default results passed to the callback are emitted immediately after `func` invokes the callback.
* In particular, if the callback is called synchronously the subscription of the resulting Observable
* will call the `next` function synchronously as well. If you want to defer that call,
* you may use `Scheduler.async` just as before. This means that by using `Scheduler.async` you can
* ensure that `func` always calls its callback asynchronously, thus avoiding terrifying Zalgo.
*
* Note that the Observable created by the output function will always emit a single value
* and then complete immediately. If `func` calls the callback multiple times, values from subsequent
* calls will not appear in the stream. If you need to listen for multiple calls,
* you probably want to use {@link fromEvent} or {@link fromEventPattern} instead.
*
* If `func` depends on some context (`this` property) and is not already bound the context of `func`
* will be the context that the output function has at call time. In particular, if `func`
* is called as a method of some objec and if `func` is not already bound, in order to preserve the context
* it is recommended that the context of the output function is set to that object as well.
*
* If the input function calls its callback in the "node style" (i.e. first argument to callback is
* optional error parameter signaling whether the call failed or not), {@link bindNodeCallback}
* provides convenient error handling and probably is a better choice.
* `bindCallback` will treat such functions the same as any other and error parameters
* (whether passed or not) will always be interpreted as regular callback argument.
*
*
* @example <caption>Convert jQuery's getJSON to an Observable API</caption>
* // Suppose we have jQuery.getJSON('/my/url', callback)
* var getJSONAsObservable = Rx.Observable.bindCallback(jQuery.getJSON);
* var result = getJSONAsObservable('/my/url');
* result.subscribe(x => console.log(x), e => console.error(e));
*
*
* @example <caption>Receive an array of arguments passed to a callback</caption>
* someFunction((a, b, c) => {
* console.log(a); // 5
* console.log(b); // 'some string'
* console.log(c); // {someProperty: 'someValue'}
* });
*
* const boundSomeFunction = Rx.Observable.bindCallback(someFunction);
* boundSomeFunction().subscribe(values => {
* console.log(values) // [5, 'some string', {someProperty: 'someValue'}]
* });
*
*
* @example <caption>Use bindCallback with a selector function</caption>
* someFunction((a, b, c) => {
* console.log(a); // 'a'
* console.log(b); // 'b'
* console.log(c); // 'c'
* });
*
* const boundSomeFunction = Rx.Observable.bindCallback(someFunction, (a, b, c) => a + b + c);
* boundSomeFunction().subscribe(value => {
* console.log(value) // 'abc'
* });
*
*
* @example <caption>Compare behaviour with and without async Scheduler</caption>
* function iCallMyCallbackSynchronously(cb) {
* cb();
* }
*
* const boundSyncFn = Rx.Observable.bindCallback(iCallMyCallbackSynchronously);
* const boundAsyncFn = Rx.Observable.bindCallback(iCallMyCallbackSynchronously, null, Rx.Scheduler.async);
*
* boundSyncFn().subscribe(() => console.log('I was sync!'));
* boundAsyncFn().subscribe(() => console.log('I was async!'));
* console.log('This happened...');
*
* // Logs:
* // I was sync!
* // This happened...
* // I was async!
*
*
* @example <caption>Use bindCallback on an object method</caption>
* const boundMethod = Rx.Observable.bindCallback(someObject.methodWithCallback);
* boundMethod.call(someObject) // make sure methodWithCallback has access to someObject
* .subscribe(subscriber);
*
*
* @see {@link bindNodeCallback}
* @see {@link from}
* @see {@link fromPromise}
*
* @param {function} func A function with a callback as the last parameter.
* @param {function} [selector] A function which takes the arguments from the
* callback and maps them to a value that is emitted on the output Observable.
* @param {Scheduler} [scheduler] The scheduler on which to schedule the
* callbacks.
* @return {function(...params: *): Observable} A function which returns the
* Observable that delivers the same values the callback would deliver.
* @static true
* @name bindCallback
* @owner Observable
*/
static create<T>(func: Function,
selector: Function | void = undefined,
scheduler?: IScheduler): (...args: any[]) => Observable<T> {
return function(this: any, ...args: any[]): Observable<T> {
return new BoundCallbackObservable<T>(func, <any>selector, args, this, scheduler);
};
}
constructor(private callbackFunc: Function,
private selector: Function,
private args: any[],
private context: any,
private scheduler: IScheduler) {
super();
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T | T[]>): Subscription {
const callbackFunc = this.callbackFunc;
const args = this.args;
const scheduler = this.scheduler;
let subject = this.subject;
if (!scheduler) {
if (!subject) {
subject = this.subject = new AsyncSubject<T>();
const handler = function handlerFn(this: any, ...innerArgs: any[]) {
const source = (<any>handlerFn).source;
const { selector, subject } = source;
if (selector) {
const result = tryCatch(selector).apply(this, innerArgs);
if (result === errorObject) {
subject.error(errorObject.e);
} else {
subject.next(result);
subject.complete();
}
} else {
subject.next(innerArgs.length <= 1 ? innerArgs[0] : innerArgs);
subject.complete();
}
};
// use named function instance to avoid closure.
(<any>handler).source = this;
const result = tryCatch(callbackFunc).apply(this.context, args.concat(handler));
if (result === errorObject) {
subject.error(errorObject.e);
}
}
return subject.subscribe(subscriber);
} else {
return scheduler.schedule(BoundCallbackObservable.dispatch, 0, { source: this, subscriber, context: this.context });
}
}
static dispatch<T>(state: { source: BoundCallbackObservable<T>, subscriber: Subscriber<T>, context: any }) {
const self = (<Subscription><any>this);
const { source, subscriber, context } = state;
const { callbackFunc, args, scheduler } = source;
let subject = source.subject;
if (!subject) {
subject = source.subject = new AsyncSubject<T>();
const handler = function handlerFn(this: any, ...innerArgs: any[]) {
const source = (<any>handlerFn).source;
const { selector, subject } = source;
if (selector) {
const result = tryCatch(selector).apply(this, innerArgs);
if (result === errorObject) {
self.add(scheduler.schedule(dispatchError, 0, { err: errorObject.e, subject }));
} else {
self.add(scheduler.schedule(dispatchNext, 0, { value: result, subject }));
}
} else {
const value = innerArgs.length <= 1 ? innerArgs[0] : innerArgs;
self.add(scheduler.schedule(dispatchNext, 0, { value, subject }));
}
};
// use named function to pass values in without closure
(<any>handler).source = source;
const result = tryCatch(callbackFunc).apply(context, args.concat(handler));
if (result === errorObject) {
subject.error(errorObject.e);
}
}
self.add(subject.subscribe(subscriber));
}
}
interface DispatchNextArg<T> {
subject: AsyncSubject<T>;
value: T;
}
function dispatchNext<T>(arg: DispatchNextArg<T>) {
const { value, subject } = arg;
subject.next(value);
subject.complete();
}
interface DispatchErrorArg<T> {
subject: AsyncSubject<T>;
err: any;
}
function dispatchError<T>(arg: DispatchErrorArg<T>) {
const { err, subject } = arg;
subject.error(err);
}
@@ -0,0 +1,279 @@
import { Observable } from '../Observable';
import { Subscriber } from '../Subscriber';
import { Subscription } from '../Subscription';
import { IScheduler } from '../Scheduler';
import { Action } from '../scheduler/Action';
import { tryCatch } from '../util/tryCatch';
import { errorObject } from '../util/errorObject';
import { AsyncSubject } from '../AsyncSubject';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class BoundNodeCallbackObservable<T> extends Observable<T> {
subject: AsyncSubject<T>;
/* tslint:disable:max-line-length */
static create<R>(callbackFunc: (callback: (err: any, result: R) => any) => any, selector?: void, scheduler?: IScheduler): () => Observable<R>;
static create<T, R>(callbackFunc: (v1: T, callback: (err: any, result: R) => any) => any, selector?: void, scheduler?: IScheduler): (v1: T) => Observable<R>;
static create<T, T2, R>(callbackFunc: (v1: T, v2: T2, callback: (err: any, result: R) => any) => any, selector?: void, scheduler?: IScheduler): (v1: T, v2: T2) => Observable<R>;
static create<T, T2, T3, R>(callbackFunc: (v1: T, v2: T2, v3: T3, callback: (err: any, result: R) => any) => any, selector?: void, scheduler?: IScheduler): (v1: T, v2: T2, v3: T3) => Observable<R>;
static create<T, T2, T3, T4, R>(callbackFunc: (v1: T, v2: T2, v3: T3, v4: T4, callback: (err: any, result: R) => any) => any, selector?: void, scheduler?: IScheduler): (v1: T, v2: T2, v3: T3, v4: T4) => Observable<R>;
static create<T, T2, T3, T4, T5, R>(callbackFunc: (v1: T, v2: T2, v3: T3, v4: T4, v5: T5, callback: (err: any, result: R) => any) => any, selector?: void, scheduler?: IScheduler): (v1: T, v2: T2, v3: T3, v4: T4, v5: T5) => Observable<R>;
static create<T, T2, T3, T4, T5, T6, R>(callbackFunc: (v1: T, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6, callback: (err: any, result: R) => any) => any, selector?: void, scheduler?: IScheduler): (v1: T, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6) => Observable<R>;
static create<T>(callbackFunc: Function, selector?: void, scheduler?: IScheduler): (...args: any[]) => Observable<T>;
static create<T>(callbackFunc: Function, selector?: (...args: any[]) => T, scheduler?: IScheduler): (...args: any[]) => Observable<T>;
/* tslint:enable:max-line-length */
/**
* Converts a Node.js-style callback API to a function that returns an
* Observable.
*
* <span class="informal">It's just like {@link bindCallback}, but the
* callback is expected to be of type `callback(error, result)`.</span>
*
* `bindNodeCallback` is not an operator because its input and output are not
* Observables. The input is a function `func` with some parameters, but the
* last parameter must be a callback function that `func` calls when it is
* done. The callback function is expected to follow Node.js conventions,
* where the first argument to the callback is an error object, signaling
* whether call was successful. If that object is passed to callback, it means
* something went wrong.
*
* The output of `bindNodeCallback` is a function that takes the same
* parameters as `func`, except the last one (the callback). When the output
* function is called with arguments, it will return an Observable.
* If `func` calls its callback with error parameter present, Observable will
* error with that value as well. If error parameter is not passed, Observable will emit
* second parameter. If there are more parameters (third and so on),
* Observable will emit an array with all arguments, except first error argument.
*
* Optionally `bindNodeCallback` accepts selector function, which allows you to
* make resulting Observable emit value computed by selector, instead of regular
* callback arguments. It works similarly to {@link bindCallback} selector, but
* Node.js-style error argument will never be passed to that function.
*
* Note that `func` will not be called at the same time output function is,
* but rather whenever resulting Observable is subscribed. By default call to
* `func` will happen synchronously after subscription, but that can be changed
* with proper {@link Scheduler} provided as optional third parameter. Scheduler
* can also control when values from callback will be emitted by Observable.
* To find out more, check out documentation for {@link bindCallback}, where
* Scheduler works exactly the same.
*
* As in {@link bindCallback}, context (`this` property) of input function will be set to context
* of returned function, when it is called.
*
* After Observable emits value, it will complete immediately. This means
* even if `func` calls callback again, values from second and consecutive
* calls will never appear on the stream. If you need to handle functions
* that call callbacks multiple times, check out {@link fromEvent} or
* {@link fromEventPattern} instead.
*
* Note that `bindNodeCallback` can be used in non-Node.js environments as well.
* "Node.js-style" callbacks are just a convention, so if you write for
* browsers or any other environment and API you use implements that callback style,
* `bindNodeCallback` can be safely used on that API functions as well.
*
* Remember that Error object passed to callback does not have to be an instance
* of JavaScript built-in `Error` object. In fact, it does not even have to an object.
* Error parameter of callback function is interpreted as "present", when value
* of that parameter is truthy. It could be, for example, non-zero number, non-empty
* string or boolean `true`. In all of these cases resulting Observable would error
* with that value. This means usually regular style callbacks will fail very often when
* `bindNodeCallback` is used. If your Observable errors much more often then you
* would expect, check if callback really is called in Node.js-style and, if not,
* switch to {@link bindCallback} instead.
*
* Note that even if error parameter is technically present in callback, but its value
* is falsy, it still won't appear in array emitted by Observable or in selector function.
*
*
* @example <caption>Read a file from the filesystem and get the data as an Observable</caption>
* import * as fs from 'fs';
* var readFileAsObservable = Rx.Observable.bindNodeCallback(fs.readFile);
* var result = readFileAsObservable('./roadNames.txt', 'utf8');
* result.subscribe(x => console.log(x), e => console.error(e));
*
*
* @example <caption>Use on function calling callback with multiple arguments</caption>
* someFunction((err, a, b) => {
* console.log(err); // null
* console.log(a); // 5
* console.log(b); // "some string"
* });
* var boundSomeFunction = Rx.Observable.bindNodeCallback(someFunction);
* boundSomeFunction()
* .subscribe(value => {
* console.log(value); // [5, "some string"]
* });
*
*
* @example <caption>Use with selector function</caption>
* someFunction((err, a, b) => {
* console.log(err); // undefined
* console.log(a); // "abc"
* console.log(b); // "DEF"
* });
* var boundSomeFunction = Rx.Observable.bindNodeCallback(someFunction, (a, b) => a + b);
* boundSomeFunction()
* .subscribe(value => {
* console.log(value); // "abcDEF"
* });
*
*
* @example <caption>Use on function calling callback in regular style</caption>
* someFunction(a => {
* console.log(a); // 5
* });
* var boundSomeFunction = Rx.Observable.bindNodeCallback(someFunction);
* boundSomeFunction()
* .subscribe(
* value => {} // never gets called
* err => console.log(err) // 5
*);
*
*
* @see {@link bindCallback}
* @see {@link from}
* @see {@link fromPromise}
*
* @param {function} func Function with a Node.js-style callback as the last parameter.
* @param {function} [selector] A function which takes the arguments from the
* callback and maps those to a value to emit on the output Observable.
* @param {Scheduler} [scheduler] The scheduler on which to schedule the
* callbacks.
* @return {function(...params: *): Observable} A function which returns the
* Observable that delivers the same values the Node.js callback would
* deliver.
* @static true
* @name bindNodeCallback
* @owner Observable
*/
static create<T>(func: Function,
selector: Function | void = undefined,
scheduler?: IScheduler): (...args: any[]) => Observable<T> {
return function(this: any, ...args: any[]): Observable<T> {
return new BoundNodeCallbackObservable<T>(func, <any>selector, args, this, scheduler);
};
}
constructor(private callbackFunc: Function,
private selector: Function,
private args: any[],
private context: any,
public scheduler: IScheduler) {
super();
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T | T[]>): Subscription {
const callbackFunc = this.callbackFunc;
const args = this.args;
const scheduler = this.scheduler;
let subject = this.subject;
if (!scheduler) {
if (!subject) {
subject = this.subject = new AsyncSubject<T>();
const handler = function handlerFn(this: any, ...innerArgs: any[]) {
const source = (<any>handlerFn).source;
const { selector, subject } = source;
const err = innerArgs.shift();
if (err) {
subject.error(err);
} else if (selector) {
const result = tryCatch(selector).apply(this, innerArgs);
if (result === errorObject) {
subject.error(errorObject.e);
} else {
subject.next(result);
subject.complete();
}
} else {
subject.next(innerArgs.length <= 1 ? innerArgs[0] : innerArgs);
subject.complete();
}
};
// use named function instance to avoid closure.
(<any>handler).source = this;
const result = tryCatch(callbackFunc).apply(this.context, args.concat(handler));
if (result === errorObject) {
subject.error(errorObject.e);
}
}
return subject.subscribe(subscriber);
} else {
return scheduler.schedule(dispatch, 0, { source: this, subscriber, context: this.context });
}
}
}
interface DispatchState<T> {
source: BoundNodeCallbackObservable<T>;
subscriber: Subscriber<T>;
context: any;
}
function dispatch<T>(this: Action<DispatchState<T>>, state: DispatchState<T>) {
const self = (<Subscription> this);
const { source, subscriber, context } = state;
// XXX: cast to `any` to access to the private field in `source`.
const { callbackFunc, args, scheduler } = source as any;
let subject = source.subject;
if (!subject) {
subject = source.subject = new AsyncSubject<T>();
const handler = function handlerFn(this: any, ...innerArgs: any[]) {
const source = (<any>handlerFn).source;
const { selector, subject } = source;
const err = innerArgs.shift();
if (err) {
self.add(scheduler.schedule(dispatchError, 0, { err, subject }));
} else if (selector) {
const result = tryCatch(selector).apply(this, innerArgs);
if (result === errorObject) {
self.add(scheduler.schedule(dispatchError, 0, { err: errorObject.e, subject }));
} else {
self.add(scheduler.schedule(dispatchNext, 0, { value: result, subject }));
}
} else {
const value = innerArgs.length <= 1 ? innerArgs[0] : innerArgs;
self.add(scheduler.schedule(dispatchNext, 0, { value, subject }));
}
};
// use named function to pass values in without closure
(<any>handler).source = source;
const result = tryCatch(callbackFunc).apply(context, args.concat(handler));
if (result === errorObject) {
self.add(scheduler.schedule(dispatchError, 0, { err: errorObject.e, subject }));
}
}
self.add(subject.subscribe(subscriber));
}
interface DispatchNextArg<T> {
subject: AsyncSubject<T>;
value: T;
}
function dispatchNext<T>(arg: DispatchNextArg<T>) {
const { value, subject } = arg;
subject.next(value);
subject.complete();
}
interface DispatchErrorArg<T> {
subject: AsyncSubject<T>;
err: any;
}
function dispatchError<T>(arg: DispatchErrorArg<T>) {
const { err, subject } = arg;
subject.error(err);
}
+180
View File
@@ -0,0 +1,180 @@
import { Subject, SubjectSubscriber } from '../Subject';
import { Operator } from '../Operator';
import { Observable } from '../Observable';
import { Subscriber } from '../Subscriber';
import { Subscription, TeardownLogic } from '../Subscription';
import { refCount as higherOrderRefCount } from '../operators/refCount';
/**
* @class ConnectableObservable<T>
*/
export class ConnectableObservable<T> extends Observable<T> {
/** @deprecated internal use only */ public _subject: Subject<T>;
/** @deprecated internal use only */ public _refCount: number = 0;
/** @deprecated internal use only */ public _connection: Subscription;
_isComplete = false;
constructor(/** @deprecated internal use only */ public source: Observable<T>,
/** @deprecated internal use only */ public subjectFactory: () => Subject<T>) {
super();
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>) {
return this.getSubject().subscribe(subscriber);
}
/** @deprecated internal use only */ public getSubject(): Subject<T> {
const subject = this._subject;
if (!subject || subject.isStopped) {
this._subject = this.subjectFactory();
}
return this._subject;
}
connect(): Subscription {
let connection = this._connection;
if (!connection) {
this._isComplete = false;
connection = this._connection = new Subscription();
connection.add(this.source
.subscribe(new ConnectableSubscriber(this.getSubject(), this)));
if (connection.closed) {
this._connection = null;
connection = Subscription.EMPTY;
} else {
this._connection = connection;
}
}
return connection;
}
refCount(): Observable<T> {
return higherOrderRefCount()(this) as Observable<T>;
}
}
const connectableProto = <any>ConnectableObservable.prototype;
export const connectableObservableDescriptor: PropertyDescriptorMap = {
operator: { value: null },
_refCount: { value: 0, writable: true },
_subject: { value: null, writable: true },
_connection: { value: null, writable: true },
_subscribe: { value: connectableProto._subscribe },
_isComplete: { value: connectableProto._isComplete, writable: true },
getSubject: { value: connectableProto.getSubject },
connect: { value: connectableProto.connect },
refCount: { value: connectableProto.refCount }
};
class ConnectableSubscriber<T> extends SubjectSubscriber<T> {
constructor(destination: Subject<T>,
private connectable: ConnectableObservable<T>) {
super(destination);
}
protected _error(err: any): void {
this._unsubscribe();
super._error(err);
}
protected _complete(): void {
this.connectable._isComplete = true;
this._unsubscribe();
super._complete();
}
/** @deprecated internal use only */ _unsubscribe() {
const connectable = <any>this.connectable;
if (connectable) {
this.connectable = null;
const connection = connectable._connection;
connectable._refCount = 0;
connectable._subject = null;
connectable._connection = null;
if (connection) {
connection.unsubscribe();
}
}
}
}
class RefCountOperator<T> implements Operator<T, T> {
constructor(private connectable: ConnectableObservable<T>) {
}
call(subscriber: Subscriber<T>, source: any): TeardownLogic {
const { connectable } = this;
(<any> connectable)._refCount++;
const refCounter = new RefCountSubscriber(subscriber, connectable);
const subscription = source.subscribe(refCounter);
if (!refCounter.closed) {
(<any> refCounter).connection = connectable.connect();
}
return subscription;
}
}
class RefCountSubscriber<T> extends Subscriber<T> {
private connection: Subscription;
constructor(destination: Subscriber<T>,
private connectable: ConnectableObservable<T>) {
super(destination);
}
/** @deprecated internal use only */ _unsubscribe() {
const { connectable } = this;
if (!connectable) {
this.connection = null;
return;
}
this.connectable = null;
const refCount = (<any> connectable)._refCount;
if (refCount <= 0) {
this.connection = null;
return;
}
(<any> connectable)._refCount = refCount - 1;
if (refCount > 1) {
this.connection = null;
return;
}
///
// Compare the local RefCountSubscriber's connection Subscription to the
// connection Subscription on the shared ConnectableObservable. In cases
// where the ConnectableObservable source synchronously emits values, and
// the RefCountSubscriber's downstream Observers synchronously unsubscribe,
// execution continues to here before the RefCountOperator has a chance to
// supply the RefCountSubscriber with the shared connection Subscription.
// For example:
// ```
// Observable.range(0, 10)
// .publish()
// .refCount()
// .take(5)
// .subscribe();
// ```
// In order to account for this case, RefCountSubscriber should only dispose
// the ConnectableObservable's shared connection Subscription if the
// connection Subscription exists, *and* either:
// a. RefCountSubscriber doesn't have a reference to the shared connection
// Subscription yet, or,
// b. RefCountSubscriber's connection Subscription reference is identical
// to the shared connection Subscription
///
const { connection } = this;
const sharedConnection = (<any> connectable)._connection;
this.connection = null;
if (sharedConnection && (!connection || sharedConnection === connection)) {
sharedConnection.unsubscribe();
}
}
}
+94
View File
@@ -0,0 +1,94 @@
import { Observable, SubscribableOrPromise } from '../Observable';
import { Subscriber } from '../Subscriber';
import { Subscription } from '../Subscription';
import { subscribeToResult } from '../util/subscribeToResult';
import { OuterSubscriber } from '../OuterSubscriber';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class DeferObservable<T> extends Observable<T> {
/**
* Creates an Observable that, on subscribe, calls an Observable factory to
* make an Observable for each new Observer.
*
* <span class="informal">Creates the Observable lazily, that is, only when it
* is subscribed.
* </span>
*
* <img src="./img/defer.png" width="100%">
*
* `defer` allows you to create the Observable only when the Observer
* subscribes, and create a fresh Observable for each Observer. It waits until
* an Observer subscribes to it, and then it generates an Observable,
* typically with an Observable factory function. It does this afresh for each
* subscriber, so although each subscriber may think it is subscribing to the
* same Observable, in fact each subscriber gets its own individual
* Observable.
*
* @example <caption>Subscribe to either an Observable of clicks or an Observable of interval, at random</caption>
* var clicksOrInterval = Rx.Observable.defer(function () {
* if (Math.random() > 0.5) {
* return Rx.Observable.fromEvent(document, 'click');
* } else {
* return Rx.Observable.interval(1000);
* }
* });
* clicksOrInterval.subscribe(x => console.log(x));
*
* // Results in the following behavior:
* // If the result of Math.random() is greater than 0.5 it will listen
* // for clicks anywhere on the "document"; when document is clicked it
* // will log a MouseEvent object to the console. If the result is less
* // than 0.5 it will emit ascending numbers, one every second(1000ms).
*
* @see {@link create}
*
* @param {function(): SubscribableOrPromise} observableFactory The Observable
* factory function to invoke for each Observer that subscribes to the output
* Observable. May also return a Promise, which will be converted on the fly
* to an Observable.
* @return {Observable} An Observable whose Observers' subscriptions trigger
* an invocation of the given Observable factory function.
* @static true
* @name defer
* @owner Observable
*/
static create<T>(observableFactory: () => SubscribableOrPromise<T> | void): Observable<T> {
return new DeferObservable(observableFactory);
}
constructor(private observableFactory: () => SubscribableOrPromise<T> | void) {
super();
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): Subscription {
return new DeferSubscriber(subscriber, this.observableFactory);
}
}
class DeferSubscriber<T> extends OuterSubscriber<T, T> {
constructor(destination: Subscriber<T>,
private factory: () => SubscribableOrPromise<T> | void) {
super(destination);
this.tryDefer();
}
private tryDefer(): void {
try {
this._callFactory();
} catch (err) {
this._error(err);
}
}
private _callFactory(): void {
const result = this.factory();
if (result) {
this.add(subscribeToResult(this, result));
}
}
}
+83
View File
@@ -0,0 +1,83 @@
import { IScheduler } from '../Scheduler';
import { Subscriber } from '../Subscriber';
import { Observable } from '../Observable';
import { TeardownLogic } from '../Subscription';
export interface DispatchArg<T> {
subscriber: Subscriber<T>;
}
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class EmptyObservable<T> extends Observable<T> {
/**
* Creates an Observable that emits no items to the Observer and immediately
* emits a complete notification.
*
* <span class="informal">Just emits 'complete', and nothing else.
* </span>
*
* <img src="./img/empty.png" width="100%">
*
* This static operator is useful for creating a simple Observable that only
* emits the complete notification. It can be used for composing with other
* Observables, such as in a {@link mergeMap}.
*
* @example <caption>Emit the number 7, then complete.</caption>
* var result = Rx.Observable.empty().startWith(7);
* result.subscribe(x => console.log(x));
*
* @example <caption>Map and flatten only odd numbers to the sequence 'a', 'b', 'c'</caption>
* var interval = Rx.Observable.interval(1000);
* var result = interval.mergeMap(x =>
* x % 2 === 1 ? Rx.Observable.of('a', 'b', 'c') : Rx.Observable.empty()
* );
* result.subscribe(x => console.log(x));
*
* // Results in the following to the console:
* // x is equal to the count on the interval eg(0,1,2,3,...)
* // x will occur every 1000ms
* // if x % 2 is equal to 1 print abc
* // if x % 2 is not equal to 1 nothing will be output
*
* @see {@link create}
* @see {@link never}
* @see {@link of}
* @see {@link throw}
*
* @param {Scheduler} [scheduler] A {@link IScheduler} to use for scheduling
* the emission of the complete notification.
* @return {Observable} An "empty" Observable: emits only the complete
* notification.
* @static true
* @name empty
* @owner Observable
*/
static create<T>(scheduler?: IScheduler): Observable<T> {
return new EmptyObservable<T>(scheduler);
}
static dispatch<T>(arg: DispatchArg<T>) {
const { subscriber } = arg;
subscriber.complete();
}
constructor(private scheduler?: IScheduler) {
super();
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): TeardownLogic {
const scheduler = this.scheduler;
if (scheduler) {
return scheduler.schedule(EmptyObservable.dispatch, 0, { subscriber });
} else {
subscriber.complete();
}
}
}
+85
View File
@@ -0,0 +1,85 @@
import { IScheduler } from '../Scheduler';
import { Observable } from '../Observable';
import { TeardownLogic } from '../Subscription';
import { Subscriber } from '../Subscriber';
export interface DispatchArg {
error: any;
subscriber: any;
}
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class ErrorObservable extends Observable<any> {
/**
* Creates an Observable that emits no items to the Observer and immediately
* emits an error notification.
*
* <span class="informal">Just emits 'error', and nothing else.
* </span>
*
* <img src="./img/throw.png" width="100%">
*
* This static operator is useful for creating a simple Observable that only
* emits the error notification. It can be used for composing with other
* Observables, such as in a {@link mergeMap}.
*
* @example <caption>Emit the number 7, then emit an error.</caption>
* var result = Rx.Observable.throw(new Error('oops!')).startWith(7);
* result.subscribe(x => console.log(x), e => console.error(e));
*
* @example <caption>Map and flatten numbers to the sequence 'a', 'b', 'c', but throw an error for 13</caption>
* var interval = Rx.Observable.interval(1000);
* var result = interval.mergeMap(x =>
* x === 13 ?
* Rx.Observable.throw('Thirteens are bad') :
* Rx.Observable.of('a', 'b', 'c')
* );
* result.subscribe(x => console.log(x), e => console.error(e));
*
* @see {@link create}
* @see {@link empty}
* @see {@link never}
* @see {@link of}
*
* @param {any} error The particular Error to pass to the error notification.
* @param {Scheduler} [scheduler] A {@link IScheduler} to use for scheduling
* the emission of the error notification.
* @return {Observable} An error Observable: emits only the error notification
* using the given error argument.
* @static true
* @name throw
* @owner Observable
*/
static create(error: any, scheduler?: IScheduler): ErrorObservable {
return new ErrorObservable(error, scheduler);
}
static dispatch(arg: DispatchArg) {
const { error, subscriber } = arg;
subscriber.error(error);
}
constructor(public error: any, private scheduler?: IScheduler) {
super();
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<any>): TeardownLogic {
const error = this.error;
const scheduler = this.scheduler;
subscriber.syncErrorThrowable = true;
if (scheduler) {
return scheduler.schedule(ErrorObservable.dispatch, 0, {
error, subscriber
});
} else {
subscriber.error(error);
}
}
}
+233
View File
@@ -0,0 +1,233 @@
import { Observable, SubscribableOrPromise } from '../Observable';
import { Subscriber } from '../Subscriber';
import { Subscription } from '../Subscription';
import { EmptyObservable } from './EmptyObservable';
import { isArray } from '../util/isArray';
import { subscribeToResult } from '../util/subscribeToResult';
import { OuterSubscriber } from '../OuterSubscriber';
import { InnerSubscriber } from '../InnerSubscriber';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class ForkJoinObservable<T> extends Observable<T> {
constructor(private sources: Array<SubscribableOrPromise<any>>,
private resultSelector?: (...values: Array<any>) => T) {
super();
}
/* tslint:disable:max-line-length */
static create<T, T2>(v1: SubscribableOrPromise<T>, v2: SubscribableOrPromise<T2>): Observable<[T, T2]>;
static create<T, T2, T3>(v1: SubscribableOrPromise<T>, v2: SubscribableOrPromise<T2>, v3: SubscribableOrPromise<T3>): Observable<[T, T2, T3]>;
static create<T, T2, T3, T4>(v1: SubscribableOrPromise<T>, v2: SubscribableOrPromise<T2>, v3: SubscribableOrPromise<T3>, v4: SubscribableOrPromise<T4>): Observable<[T, T2, T3, T4]>;
static create<T, T2, T3, T4, T5>(v1: SubscribableOrPromise<T>, v2: SubscribableOrPromise<T2>, v3: SubscribableOrPromise<T3>, v4: SubscribableOrPromise<T4>, v5: SubscribableOrPromise<T5>): Observable<[T, T2, T3, T4, T5]>;
static create<T, T2, T3, T4, T5, T6>(v1: SubscribableOrPromise<T>, v2: SubscribableOrPromise<T2>, v3: SubscribableOrPromise<T3>, v4: SubscribableOrPromise<T4>, v5: SubscribableOrPromise<T5>, v6: SubscribableOrPromise<T6>): Observable<[T, T2, T3, T4, T5, T6]>;
static create<T, R>(v1: SubscribableOrPromise<T>, project: (v1: T) => R): Observable<R>;
static create<T, T2, R>(v1: SubscribableOrPromise<T>, v2: SubscribableOrPromise<T2>, project: (v1: T, v2: T2) => R): Observable<R>;
static create<T, T2, T3, R>(v1: SubscribableOrPromise<T>, v2: SubscribableOrPromise<T2>, v3: SubscribableOrPromise<T3>, project: (v1: T, v2: T2, v3: T3) => R): Observable<R>;
static create<T, T2, T3, T4, R>(v1: SubscribableOrPromise<T>, v2: SubscribableOrPromise<T2>, v3: SubscribableOrPromise<T3>, v4: SubscribableOrPromise<T4>, project: (v1: T, v2: T2, v3: T3, v4: T4) => R): Observable<R>;
static create<T, T2, T3, T4, T5, R>(v1: SubscribableOrPromise<T>, v2: SubscribableOrPromise<T2>, v3: SubscribableOrPromise<T3>, v4: SubscribableOrPromise<T4>, v5: SubscribableOrPromise<T5>, project: (v1: T, v2: T2, v3: T3, v4: T4, v5: T5) => R): Observable<R>;
static create<T, T2, T3, T4, T5, T6, R>(v1: SubscribableOrPromise<T>, v2: SubscribableOrPromise<T2>, v3: SubscribableOrPromise<T3>, v4: SubscribableOrPromise<T4>, v5: SubscribableOrPromise<T5>, v6: SubscribableOrPromise<T6>, project: (v1: T, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6) => R): Observable<R>;
static create<T>(sources: SubscribableOrPromise<T>[]): Observable<T[]>;
static create<R>(sources: SubscribableOrPromise<any>[]): Observable<R>;
static create<T, R>(sources: SubscribableOrPromise<T>[], project: (...values: Array<T>) => R): Observable<R>;
static create<R>(sources: SubscribableOrPromise<any>[], project: (...values: Array<any>) => R): Observable<R>;
static create<T>(...sources: SubscribableOrPromise<T>[]): Observable<T[]>;
static create<R>(...sources: SubscribableOrPromise<any>[]): Observable<R>;
/* tslint:enable:max-line-length */
/**
* Joins last values emitted by passed Observables.
*
* <span class="informal">Wait for Observables to complete and then combine last values they emitted.</span>
*
* <img src="./img/forkJoin.png" width="100%">
*
* `forkJoin` is an operator that takes any number of Observables which can be passed either as an array
* or directly as arguments. If no input Observables are provided, resulting stream will complete
* immediately.
*
* `forkJoin` will wait for all passed Observables to complete and then it will emit an array with last
* values from corresponding Observables. So if you pass `n` Observables to the operator, resulting
* array will have `n` values, where first value is the last thing emitted by the first Observable,
* second value is the last thing emitted by the second Observable and so on. That means `forkJoin` will
* not emit more than once and it will complete after that. If you need to emit combined values not only
* at the end of lifecycle of passed Observables, but also throughout it, try out {@link combineLatest}
* or {@link zip} instead.
*
* In order for resulting array to have the same length as the number of input Observables, whenever any of
* that Observables completes without emitting any value, `forkJoin` will complete at that moment as well
* and it will not emit anything either, even if it already has some last values from other Observables.
* Conversely, if there is an Observable that never completes, `forkJoin` will never complete as well,
* unless at any point some other Observable completes without emitting value, which brings us back to
* the previous case. Overall, in order for `forkJoin` to emit a value, all Observables passed as arguments
* have to emit something at least once and complete.
*
* If any input Observable errors at some point, `forkJoin` will error as well and all other Observables
* will be immediately unsubscribed.
*
* Optionally `forkJoin` accepts project function, that will be called with values which normally
* would land in emitted array. Whatever is returned by project function, will appear in output
* Observable instead. This means that default project can be thought of as a function that takes
* all its arguments and puts them into an array. Note that project function will be called only
* when output Observable is supposed to emit a result.
*
* @example <caption>Use forkJoin with operator emitting immediately</caption>
* const observable = Rx.Observable.forkJoin(
* Rx.Observable.of(1, 2, 3, 4),
* Rx.Observable.of(5, 6, 7, 8)
* );
* observable.subscribe(
* value => console.log(value),
* err => {},
* () => console.log('This is how it ends!')
* );
*
* // Logs:
* // [4, 8]
* // "This is how it ends!"
*
*
* @example <caption>Use forkJoin with operator emitting after some time</caption>
* const observable = Rx.Observable.forkJoin(
* Rx.Observable.interval(1000).take(3), // emit 0, 1, 2 every second and complete
* Rx.Observable.interval(500).take(4) // emit 0, 1, 2, 3 every half a second and complete
* );
* observable.subscribe(
* value => console.log(value),
* err => {},
* () => console.log('This is how it ends!')
* );
*
* // Logs:
* // [2, 3] after 3 seconds
* // "This is how it ends!" immediately after
*
*
* @example <caption>Use forkJoin with project function</caption>
* const observable = Rx.Observable.forkJoin(
* Rx.Observable.interval(1000).take(3), // emit 0, 1, 2 every second and complete
* Rx.Observable.interval(500).take(4), // emit 0, 1, 2, 3 every half a second and complete
* (n, m) => n + m
* );
* observable.subscribe(
* value => console.log(value),
* err => {},
* () => console.log('This is how it ends!')
* );
*
* // Logs:
* // 5 after 3 seconds
* // "This is how it ends!" immediately after
*
* @see {@link combineLatest}
* @see {@link zip}
*
* @param {...SubscribableOrPromise} sources Any number of Observables provided either as an array or as an arguments
* passed directly to the operator.
* @param {function} [project] Function that takes values emitted by input Observables and returns value
* that will appear in resulting Observable instead of default array.
* @return {Observable} Observable emitting either an array of last values emitted by passed Observables
* or value from project function.
* @static true
* @name forkJoin
* @owner Observable
*/
static create<T>(...sources: Array<SubscribableOrPromise<any> |
Array<SubscribableOrPromise<any>> |
((...values: Array<any>) => any)>): Observable<T> {
if (sources === null || arguments.length === 0) {
return new EmptyObservable<T>();
}
let resultSelector: (...values: Array<any>) => any = null;
if (typeof sources[sources.length - 1] === 'function') {
resultSelector = <(...values: Array<any>) => any>sources.pop();
}
// if the first and only other argument besides the resultSelector is an array
// assume it's been called with `forkJoin([obs1, obs2, obs3], resultSelector)`
if (sources.length === 1 && isArray(sources[0])) {
sources = <Array<SubscribableOrPromise<any>>>sources[0];
}
if (sources.length === 0) {
return new EmptyObservable<T>();
}
return new ForkJoinObservable(<Array<SubscribableOrPromise<any>>>sources, resultSelector);
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<any>): Subscription {
return new ForkJoinSubscriber(subscriber, this.sources, this.resultSelector);
}
}
/**
* We need this JSDoc comment for affecting ESDoc.
* @ignore
* @extends {Ignored}
*/
class ForkJoinSubscriber<T> extends OuterSubscriber<T, T> {
private completed = 0;
private total: number;
private values: any[];
private haveValues = 0;
constructor(destination: Subscriber<T>,
private sources: Array<SubscribableOrPromise<any>>,
private resultSelector?: (...values: Array<any>) => T) {
super(destination);
const len = sources.length;
this.total = len;
this.values = new Array(len);
for (let i = 0; i < len; i++) {
const source = sources[i];
const innerSubscription = subscribeToResult(this, source, null, i);
if (innerSubscription) {
(<any> innerSubscription).outerIndex = i;
this.add(innerSubscription);
}
}
}
notifyNext(outerValue: any, innerValue: T,
outerIndex: number, innerIndex: number,
innerSub: InnerSubscriber<T, T>): void {
this.values[outerIndex] = innerValue;
if (!(<any>innerSub)._hasValue) {
(<any>innerSub)._hasValue = true;
this.haveValues++;
}
}
notifyComplete(innerSub: InnerSubscriber<T, T>): void {
const destination = this.destination;
const { haveValues, resultSelector, values } = this;
const len = values.length;
if (!(<any>innerSub)._hasValue) {
destination.complete();
return;
}
this.completed++;
if (this.completed !== len) {
return;
}
if (haveValues === len) {
const value = resultSelector ? resultSelector.apply(this, values) : values;
destination.next(value);
}
destination.complete();
}
}
+244
View File
@@ -0,0 +1,244 @@
import { Observable } from '../Observable';
import { tryCatch } from '../util/tryCatch';
import { isFunction } from '../util/isFunction';
import { errorObject } from '../util/errorObject';
import { Subscription } from '../Subscription';
import { Subscriber } from '../Subscriber';
const toString: Function = Object.prototype.toString;
export type NodeStyleEventEmitter = {
addListener: (eventName: string, handler: NodeEventHandler) => void;
removeListener: (eventName: string, handler: NodeEventHandler) => void;
};
export type NodeEventHandler = (...args: any[]) => void;
function isNodeStyleEventEmitter(sourceObj: any): sourceObj is NodeStyleEventEmitter {
return !!sourceObj && typeof sourceObj.addListener === 'function' && typeof sourceObj.removeListener === 'function';
}
export type JQueryStyleEventEmitter = {
on: (eventName: string, handler: Function) => void;
off: (eventName: string, handler: Function) => void;
};
function isJQueryStyleEventEmitter(sourceObj: any): sourceObj is JQueryStyleEventEmitter {
return !!sourceObj && typeof sourceObj.on === 'function' && typeof sourceObj.off === 'function';
}
function isNodeList(sourceObj: any): sourceObj is NodeList {
return !!sourceObj && toString.call(sourceObj) === '[object NodeList]';
}
function isHTMLCollection(sourceObj: any): sourceObj is HTMLCollection {
return !!sourceObj && toString.call(sourceObj) === '[object HTMLCollection]';
}
function isEventTarget(sourceObj: any): sourceObj is EventTarget {
return !!sourceObj && typeof sourceObj.addEventListener === 'function' && typeof sourceObj.removeEventListener === 'function';
}
export type EventTargetLike = EventTarget | NodeStyleEventEmitter | JQueryStyleEventEmitter | NodeList | HTMLCollection;
export type EventListenerOptions = {
capture?: boolean;
passive?: boolean;
once?: boolean;
} | boolean;
export type SelectorMethodSignature<T> = (...args: Array<any>) => T;
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class FromEventObservable<T> extends Observable<T> {
/* tslint:disable:max-line-length */
static create<T>(target: EventTargetLike, eventName: string): Observable<T>;
static create<T>(target: EventTargetLike, eventName: string, selector: SelectorMethodSignature<T>): Observable<T>;
static create<T>(target: EventTargetLike, eventName: string, options: EventListenerOptions): Observable<T>;
static create<T>(target: EventTargetLike, eventName: string, options: EventListenerOptions, selector: SelectorMethodSignature<T>): Observable<T>;
/* tslint:enable:max-line-length */
/**
* Creates an Observable that emits events of a specific type coming from the
* given event target.
*
* <span class="informal">Creates an Observable from DOM events, or Node.js
* EventEmitter events or others.</span>
*
* <img src="./img/fromEvent.png" width="100%">
*
* `fromEvent` accepts as a first argument event target, which is an object with methods
* for registering event handler functions. As a second argument it takes string that indicates
* type of event we want to listen for. `fromEvent` supports selected types of event targets,
* which are described in detail below. If your event target does not match any of the ones listed,
* you should use {@link fromEventPattern}, which can be used on arbitrary APIs.
* When it comes to APIs supported by `fromEvent`, their methods for adding and removing event
* handler functions have different names, but they all accept a string describing event type
* and function itself, which will be called whenever said event happens.
*
* Every time resulting Observable is subscribed, event handler function will be registered
* to event target on given event type. When that event fires, value
* passed as a first argument to registered function will be emitted by output Observable.
* When Observable is unsubscribed, function will be unregistered from event target.
*
* Note that if event target calls registered function with more than one argument, second
* and following arguments will not appear in resulting stream. In order to get access to them,
* you can pass to `fromEvent` optional project function, which will be called with all arguments
* passed to event handler. Output Observable will then emit value returned by project function,
* instead of the usual value.
*
* Remember that event targets listed below are checked via duck typing. It means that
* no matter what kind of object you have and no matter what environment you work in,
* you can safely use `fromEvent` on that object if it exposes described methods (provided
* of course they behave as was described above). So for example if Node.js library exposes
* event target which has the same method names as DOM EventTarget, `fromEvent` is still
* a good choice.
*
* If the API you use is more callback then event handler oriented (subscribed
* callback function fires only once and thus there is no need to manually
* unregister it), you should use {@link bindCallback} or {@link bindNodeCallback}
* instead.
*
* `fromEvent` supports following types of event targets:
*
* **DOM EventTarget**
*
* This is an object with `addEventListener` and `removeEventListener` methods.
*
* In the browser, `addEventListener` accepts - apart from event type string and event
* handler function arguments - optional third parameter, which is either an object or boolean,
* both used for additional configuration how and when passed function will be called. When
* `fromEvent` is used with event target of that type, you can provide this values
* as third parameter as well.
*
* **Node.js EventEmitter**
*
* An object with `addListener` and `removeListener` methods.
*
* **JQuery-style event target**
*
* An object with `on` and `off` methods
*
* **DOM NodeList**
*
* List of DOM Nodes, returned for example by `document.querySelectorAll` or `Node.childNodes`.
*
* Although this collection is not event target in itself, `fromEvent` will iterate over all Nodes
* it contains and install event handler function in every of them. When returned Observable
* is unsubscribed, function will be removed from all Nodes.
*
* **DOM HtmlCollection**
*
* Just as in case of NodeList it is a collection of DOM nodes. Here as well event handler function is
* installed and removed in each of elements.
*
*
* @example <caption>Emits clicks happening on the DOM document</caption>
* var clicks = Rx.Observable.fromEvent(document, 'click');
* clicks.subscribe(x => console.log(x));
*
* // Results in:
* // MouseEvent object logged to console every time a click
* // occurs on the document.
*
*
* @example <caption>Use addEventListener with capture option</caption>
* var clicksInDocument = Rx.Observable.fromEvent(document, 'click', true); // note optional configuration parameter
* // which will be passed to addEventListener
* var clicksInDiv = Rx.Observable.fromEvent(someDivInDocument, 'click');
*
* clicksInDocument.subscribe(() => console.log('document'));
* clicksInDiv.subscribe(() => console.log('div'));
*
* // By default events bubble UP in DOM tree, so normally
* // when we would click on div in document
* // "div" would be logged first and then "document".
* // Since we specified optional `capture` option, document
* // will catch event when it goes DOWN DOM tree, so console
* // will log "document" and then "div".
*
* @see {@link bindCallback}
* @see {@link bindNodeCallback}
* @see {@link fromEventPattern}
*
* @param {EventTargetLike} target The DOM EventTarget, Node.js
* EventEmitter, JQuery-like event target, NodeList or HTMLCollection to attach the event handler to.
* @param {string} eventName The event name of interest, being emitted by the
* `target`.
* @param {EventListenerOptions} [options] Options to pass through to addEventListener
* @param {SelectorMethodSignature<T>} [selector] An optional function to
* post-process results. It takes the arguments from the event handler and
* should return a single value.
* @return {Observable<T>}
* @static true
* @name fromEvent
* @owner Observable
*/
static create<T>(target: EventTargetLike,
eventName: string,
options?: EventListenerOptions | SelectorMethodSignature<T>,
selector?: SelectorMethodSignature<T>): Observable<T> {
if (isFunction(options)) {
selector = <any>options;
options = undefined;
}
return new FromEventObservable(target, eventName, selector, options as EventListenerOptions | undefined);
}
constructor(private sourceObj: EventTargetLike,
private eventName: string,
private selector?: SelectorMethodSignature<T>,
private options?: EventListenerOptions) {
super();
}
private static setupSubscription<T>(sourceObj: EventTargetLike,
eventName: string,
handler: Function,
subscriber: Subscriber<T>,
options?: EventListenerOptions) {
let unsubscribe: () => void;
if (isNodeList(sourceObj) || isHTMLCollection(sourceObj)) {
for (let i = 0, len = sourceObj.length; i < len; i++) {
FromEventObservable.setupSubscription(sourceObj[i], eventName, handler, subscriber, options);
}
} else if (isEventTarget(sourceObj)) {
const source = sourceObj;
sourceObj.addEventListener(eventName, <EventListener>handler, <boolean>options);
unsubscribe = () => source.removeEventListener(eventName, <EventListener>handler, <boolean>options);
} else if (isJQueryStyleEventEmitter(sourceObj)) {
const source = sourceObj;
sourceObj.on(eventName, handler);
unsubscribe = () => source.off(eventName, handler);
} else if (isNodeStyleEventEmitter(sourceObj)) {
const source = sourceObj;
sourceObj.addListener(eventName, handler as NodeEventHandler);
unsubscribe = () => source.removeListener(eventName, handler as NodeEventHandler);
} else {
throw new TypeError('Invalid event target');
}
subscriber.add(new Subscription(unsubscribe));
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>) {
const sourceObj = this.sourceObj;
const eventName = this.eventName;
const options = this.options;
const selector = this.selector;
let handler = selector ? (...args: any[]) => {
let result = tryCatch(selector)(...args);
if (result === errorObject) {
subscriber.error(errorObject.e);
} else {
subscriber.next(result);
}
} : (e: any) => subscriber.next(e);
FromEventObservable.setupSubscription(sourceObj, eventName, handler, subscriber, options);
}
}
@@ -0,0 +1,110 @@
import { isFunction } from '../util/isFunction';
import { Observable } from '../Observable';
import { Subscription } from '../Subscription';
import { Subscriber } from '../Subscriber';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class FromEventPatternObservable<T> extends Observable<T> {
/**
* Creates an Observable from an API based on addHandler/removeHandler
* functions.
*
* <span class="informal">Converts any addHandler/removeHandler API to an
* Observable.</span>
*
* <img src="./img/fromEventPattern.png" width="100%">
*
* Creates an Observable by using the `addHandler` and `removeHandler`
* functions to add and remove the handlers, with an optional selector
* function to project the event arguments to a result. The `addHandler` is
* called when the output Observable is subscribed, and `removeHandler` is
* called when the Subscription is unsubscribed.
*
* @example <caption>Emits clicks happening on the DOM document</caption>
* function addClickHandler(handler) {
* document.addEventListener('click', handler);
* }
*
* function removeClickHandler(handler) {
* document.removeEventListener('click', handler);
* }
*
* var clicks = Rx.Observable.fromEventPattern(
* addClickHandler,
* removeClickHandler
* );
* clicks.subscribe(x => console.log(x));
*
* @see {@link from}
* @see {@link fromEvent}
*
* @param {function(handler: Function): any} addHandler A function that takes
* a `handler` function as argument and attaches it somehow to the actual
* source of events.
* @param {function(handler: Function, signal?: any): void} [removeHandler] An optional function that
* takes a `handler` function as argument and removes it in case it was
* previously attached using `addHandler`. if addHandler returns signal to teardown when remove,
* removeHandler function will forward it.
* @param {function(...args: any): T} [selector] An optional function to
* post-process results. It takes the arguments from the event handler and
* should return a single value.
* @return {Observable<T>}
* @static true
* @name fromEventPattern
* @owner Observable
*/
static create<T>(addHandler: (handler: Function) => any,
removeHandler?: (handler: Function, signal?: any) => void,
selector?: (...args: Array<any>) => T) {
return new FromEventPatternObservable(addHandler, removeHandler, selector);
}
constructor(private addHandler: (handler: Function) => any,
private removeHandler?: (handler: Function, signal?: any) => void,
private selector?: (...args: Array<any>) => T) {
super();
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>) {
const removeHandler = this.removeHandler;
const handler = !!this.selector ? (...args: Array<any>) => {
this._callSelector(subscriber, args);
} : function(e: any) { subscriber.next(e); };
const retValue = this._callAddHandler(handler, subscriber);
if (!isFunction(removeHandler)) {
return;
}
subscriber.add(new Subscription(() => {
//TODO: determine whether or not to forward to error handler
removeHandler(handler, retValue) ;
}));
}
private _callSelector(subscriber: Subscriber<T>, args: Array<any>): void {
try {
const result: T = this.selector(...args);
subscriber.next(result);
}
catch (e) {
subscriber.error(e);
}
}
private _callAddHandler(handler: (e: any) => void, errorSubscriber: Subscriber<T>): any | null {
try {
return this.addHandler(handler) || null;
}
catch (e) {
errorSubscriber.error(e);
}
}
}
+115
View File
@@ -0,0 +1,115 @@
import { isArray } from '../util/isArray';
import { isArrayLike } from '../util/isArrayLike';
import { isPromise } from '../util/isPromise';
import { PromiseObservable } from './PromiseObservable';
import { IteratorObservable } from'./IteratorObservable';
import { ArrayObservable } from './ArrayObservable';
import { ArrayLikeObservable } from './ArrayLikeObservable';
import { IScheduler } from '../Scheduler';
import { iterator as Symbol_iterator } from '../symbol/iterator';
import { Observable, ObservableInput } from '../Observable';
import { Subscriber } from '../Subscriber';
import { ObserveOnSubscriber } from '../operators/observeOn';
import { observable as Symbol_observable } from '../symbol/observable';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class FromObservable<T> extends Observable<T> {
constructor(private ish: ObservableInput<T>, private scheduler?: IScheduler) {
super(null);
}
static create<T>(ish: ObservableInput<T>, scheduler?: IScheduler): Observable<T>;
static create<T, R>(ish: ArrayLike<T>, scheduler?: IScheduler): Observable<R>;
/**
* Creates an Observable from an Array, an array-like object, a Promise, an
* iterable object, or an Observable-like object.
*
* <span class="informal">Converts almost anything to an Observable.</span>
*
* <img src="./img/from.png" width="100%">
*
* Convert various other objects and data types into Observables. `from`
* converts a Promise or an array-like or an
* [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#iterable)
* object into an Observable that emits the items in that promise or array or
* iterable. A String, in this context, is treated as an array of characters.
* Observable-like objects (contains a function named with the ES2015 Symbol
* for Observable) can also be converted through this operator.
*
* @example <caption>Converts an array to an Observable</caption>
* var array = [10, 20, 30];
* var result = Rx.Observable.from(array);
* result.subscribe(x => console.log(x));
*
* // Results in the following:
* // 10 20 30
*
* @example <caption>Convert an infinite iterable (from a generator) to an Observable</caption>
* function* generateDoubles(seed) {
* var i = seed;
* while (true) {
* yield i;
* i = 2 * i; // double it
* }
* }
*
* var iterator = generateDoubles(3);
* var result = Rx.Observable.from(iterator).take(10);
* result.subscribe(x => console.log(x));
*
* // Results in the following:
* // 3 6 12 24 48 96 192 384 768 1536
*
* @see {@link create}
* @see {@link fromEvent}
* @see {@link fromEventPattern}
* @see {@link fromPromise}
*
* @param {ObservableInput<T>} ish A subscribable object, a Promise, an
* Observable-like, an Array, an iterable or an array-like object to be
* converted.
* @param {Scheduler} [scheduler] The scheduler on which to schedule the
* emissions of values.
* @return {Observable<T>} The Observable whose values are originally from the
* input object that was converted.
* @static true
* @name from
* @owner Observable
*/
static create<T>(ish: ObservableInput<T>, scheduler?: IScheduler): Observable<T> {
if (ish != null) {
if (typeof ish[Symbol_observable] === 'function') {
if (ish instanceof Observable && !scheduler) {
return ish;
}
return new FromObservable<T>(ish, scheduler);
} else if (isArray(ish)) {
return new ArrayObservable<T>(ish, scheduler);
} else if (isPromise<T>(ish)) {
return new PromiseObservable<T>(ish, scheduler);
} else if (typeof ish[Symbol_iterator] === 'function' || typeof ish === 'string') {
return new IteratorObservable<T>(ish, scheduler);
} else if (isArrayLike(ish)) {
return new ArrayLikeObservable(ish, scheduler);
}
}
throw new TypeError((ish !== null && typeof ish || ish) + ' is not observable');
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>) {
const ish = this.ish;
const scheduler = this.scheduler;
if (scheduler == null) {
return ish[Symbol_observable]().subscribe(subscriber);
} else {
return ish[Symbol_observable]().subscribe(new ObserveOnSubscriber(subscriber, scheduler, 0));
}
}
}
+295
View File
@@ -0,0 +1,295 @@
import { IScheduler } from '../Scheduler';
import { Action } from '../scheduler/Action';
import { Observable } from '../Observable' ;
import { Subscriber } from '../Subscriber';
import { Subscription } from '../Subscription';
import { isScheduler } from '../util/isScheduler';
const selfSelector = <T>(value: T) => value;
export type ConditionFunc<S> = (state: S) => boolean;
export type IterateFunc<S> = (state: S) => S;
export type ResultFunc<S, T> = (state: S) => T;
interface SchedulerState<T, S> {
needIterate?: boolean;
state: S;
subscriber: Subscriber<T>;
condition?: ConditionFunc<S>;
iterate: IterateFunc<S>;
resultSelector: ResultFunc<S, T>;
}
export interface GenerateBaseOptions<S> {
/**
* Initial state.
*/
initialState: S;
/**
* Condition function that accepts state and returns boolean.
* When it returns false, the generator stops.
* If not specified, a generator never stops.
*/
condition?: ConditionFunc<S>;
/**
* Iterate function that accepts state and returns new state.
*/
iterate: IterateFunc<S>;
/**
* IScheduler to use for generation process.
* By default, a generator starts immediately.
*/
scheduler?: IScheduler;
}
export interface GenerateOptions<T, S> extends GenerateBaseOptions<S> {
/**
* Result selection function that accepts state and returns a value to emit.
*/
resultSelector: ResultFunc<S, T>;
}
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class GenerateObservable<T, S> extends Observable<T> {
constructor(private initialState: S,
private condition: ConditionFunc<S>,
private iterate: IterateFunc<S>,
private resultSelector: ResultFunc<S, T>,
private scheduler?: IScheduler) {
super();
}
/**
* Generates an observable sequence by running a state-driven loop
* producing the sequence's elements, using the specified scheduler
* to send out observer messages.
*
* <img src="./img/generate.png" width="100%">
*
* @example <caption>Produces sequence of 0, 1, 2, ... 9, then completes.</caption>
* var res = Rx.Observable.generate(0, x => x < 10, x => x + 1, x => x);
*
* @example <caption>Using asap scheduler, produces sequence of 2, 3, 5, then completes.</caption>
* var res = Rx.Observable.generate(1, x => x < 5, x => x * 2, x => x + 1, Rx.Scheduler.asap);
*
* @see {@link from}
* @see {@link create}
*
* @param {S} initialState Initial state.
* @param {function (state: S): boolean} condition Condition to terminate generation (upon returning false).
* @param {function (state: S): S} iterate Iteration step function.
* @param {function (state: S): T} resultSelector Selector function for results produced in the sequence.
* @param {Scheduler} [scheduler] A {@link IScheduler} on which to run the generator loop. If not provided, defaults to emit immediately.
* @returns {Observable<T>} The generated sequence.
*/
static create<T, S>(initialState: S,
condition: ConditionFunc<S>,
iterate: IterateFunc<S>,
resultSelector: ResultFunc<S, T>,
scheduler?: IScheduler): Observable<T>
/**
* Generates an observable sequence by running a state-driven loop
* producing the sequence's elements, using the specified scheduler
* to send out observer messages.
* The overload uses state as an emitted value.
*
* <img src="./img/generate.png" width="100%">
*
* @example <caption>Produces sequence of 0, 1, 2, ... 9, then completes.</caption>
* var res = Rx.Observable.generate(0, x => x < 10, x => x + 1);
*
* @example <caption>Using asap scheduler, produces sequence of 1, 2, 4, then completes.</caption>
* var res = Rx.Observable.generate(1, x => x < 5, x => x * 2, Rx.Scheduler.asap);
*
* @see {@link from}
* @see {@link create}
*
* @param {S} initialState Initial state.
* @param {function (state: S): boolean} condition Condition to terminate generation (upon returning false).
* @param {function (state: S): S} iterate Iteration step function.
* @param {Scheduler} [scheduler] A {@link IScheduler} on which to run the generator loop. If not provided, defaults to emit immediately.
* @returns {Observable<S>} The generated sequence.
*/
static create<S>(initialState: S,
condition: ConditionFunc<S>,
iterate: IterateFunc<S>,
scheduler?: IScheduler): Observable<S>
/**
* Generates an observable sequence by running a state-driven loop
* producing the sequence's elements, using the specified scheduler
* to send out observer messages.
* The overload accepts options object that might contain initial state, iterate,
* condition and scheduler.
*
* <img src="./img/generate.png" width="100%">
*
* @example <caption>Produces sequence of 0, 1, 2, ... 9, then completes.</caption>
* var res = Rx.Observable.generate({
* initialState: 0,
* condition: x => x < 10,
* iterate: x => x + 1
* });
*
* @see {@link from}
* @see {@link create}
*
* @param {GenerateBaseOptions<S>} options Object that must contain initialState, iterate and might contain condition and scheduler.
* @returns {Observable<S>} The generated sequence.
*/
static create<S>(options: GenerateBaseOptions<S>): Observable<S>
/**
* Generates an observable sequence by running a state-driven loop
* producing the sequence's elements, using the specified scheduler
* to send out observer messages.
* The overload accepts options object that might contain initial state, iterate,
* condition, result selector and scheduler.
*
* <img src="./img/generate.png" width="100%">
*
* @example <caption>Produces sequence of 0, 1, 2, ... 9, then completes.</caption>
* var res = Rx.Observable.generate({
* initialState: 0,
* condition: x => x < 10,
* iterate: x => x + 1,
* resultSelector: x => x
* });
*
* @see {@link from}
* @see {@link create}
*
* @param {GenerateOptions<T, S>} options Object that must contain initialState, iterate, resultSelector and might contain condition and scheduler.
* @returns {Observable<T>} The generated sequence.
*/
static create<T, S>(options: GenerateOptions<T, S>): Observable<T>
static create<T, S>(initialStateOrOptions: S | GenerateOptions<T, S>,
condition?: ConditionFunc<S>,
iterate?: IterateFunc<S>,
resultSelectorOrObservable?: (ResultFunc<S, T>) | IScheduler,
scheduler?: IScheduler): Observable<T> {
if (arguments.length == 1) {
return new GenerateObservable<T, S>(
(<GenerateOptions<T, S>>initialStateOrOptions).initialState,
(<GenerateOptions<T, S>>initialStateOrOptions).condition,
(<GenerateOptions<T, S>>initialStateOrOptions).iterate,
(<GenerateOptions<T, S>>initialStateOrOptions).resultSelector || selfSelector as ResultFunc<S, T>,
(<GenerateOptions<T, S>>initialStateOrOptions).scheduler);
}
if (resultSelectorOrObservable === undefined || isScheduler(resultSelectorOrObservable)) {
return new GenerateObservable<T, S>(
<S>initialStateOrOptions,
condition,
iterate,
selfSelector as ResultFunc<S, T>,
<IScheduler>resultSelectorOrObservable);
}
return new GenerateObservable<T, S>(
<S>initialStateOrOptions,
condition,
iterate,
<ResultFunc<S, T>>resultSelectorOrObservable,
<IScheduler>scheduler);
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<any>): Subscription | Function | void {
let state = this.initialState;
if (this.scheduler) {
return this.scheduler.schedule<SchedulerState<T, S>>(GenerateObservable.dispatch, 0, {
subscriber,
iterate: this.iterate,
condition: this.condition,
resultSelector: this.resultSelector,
state });
}
const { condition, resultSelector, iterate } = this;
do {
if (condition) {
let conditionResult: boolean;
try {
conditionResult = condition(state);
} catch (err) {
subscriber.error(err);
return;
}
if (!conditionResult) {
subscriber.complete();
break;
}
}
let value: T;
try {
value = resultSelector(state);
} catch (err) {
subscriber.error(err);
return;
}
subscriber.next(value);
if (subscriber.closed) {
break;
}
try {
state = iterate(state);
} catch (err) {
subscriber.error(err);
return;
}
} while (true);
}
private static dispatch<T, S>(state: SchedulerState<T, S>): Subscription | void {
const { subscriber, condition } = state;
if (subscriber.closed) {
return;
}
if (state.needIterate) {
try {
state.state = state.iterate(state.state);
} catch (err) {
subscriber.error(err);
return;
}
} else {
state.needIterate = true;
}
if (condition) {
let conditionResult: boolean;
try {
conditionResult = condition(state.state);
} catch (err) {
subscriber.error(err);
return;
}
if (!conditionResult) {
subscriber.complete();
return;
}
if (subscriber.closed) {
return;
}
}
let value: T;
try {
value = state.resultSelector(state.state);
} catch (err) {
subscriber.error(err);
return;
}
if (subscriber.closed) {
return;
}
subscriber.next(value);
if (subscriber.closed) {
return;
}
return (<Action<SchedulerState<T, S>>><any>this).schedule(state);
}
}
+59
View File
@@ -0,0 +1,59 @@
import { Observable, SubscribableOrPromise } from '../Observable';
import { Subscriber } from '../Subscriber';
import { TeardownLogic } from '../Subscription';
import { subscribeToResult } from '../util/subscribeToResult';
import { OuterSubscriber } from '../OuterSubscriber';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class IfObservable<T, R> extends Observable<T> {
static create<T, R>(condition: () => boolean | void,
thenSource?: SubscribableOrPromise<T> | void,
elseSource?: SubscribableOrPromise<R> | void): Observable<T|R> {
return new IfObservable(condition, thenSource, elseSource);
}
constructor(private condition: () => boolean | void,
private thenSource?: SubscribableOrPromise<T> | void,
private elseSource?: SubscribableOrPromise<R> | void) {
super();
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T|R>): TeardownLogic {
const { condition, thenSource, elseSource } = this;
return new IfSubscriber(subscriber, condition, thenSource, elseSource);
}
}
class IfSubscriber<T, R> extends OuterSubscriber<T, T> {
constructor(destination: Subscriber<T>,
private condition: () => boolean | void,
private thenSource?: SubscribableOrPromise<T> | void,
private elseSource?: SubscribableOrPromise<R> | void) {
super(destination);
this.tryIf();
}
private tryIf(): void {
const { condition, thenSource, elseSource } = this;
let result: boolean;
try {
result = <boolean>condition();
const source = result ? thenSource : elseSource;
if (source) {
this.add(subscribeToResult(this, source));
} else {
this._complete();
}
} catch (err) {
this._error(err);
}
}
}
+85
View File
@@ -0,0 +1,85 @@
import { Subscriber } from '../Subscriber';
import { isNumeric } from '../util/isNumeric';
import { IScheduler } from '../Scheduler';
import { Observable } from '../Observable';
import { async } from '../scheduler/async';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class IntervalObservable extends Observable<number> {
/**
* Creates an Observable that emits sequential numbers every specified
* interval of time, on a specified IScheduler.
*
* <span class="informal">Emits incremental numbers periodically in time.
* </span>
*
* <img src="./img/interval.png" width="100%">
*
* `interval` returns an Observable that emits an infinite sequence of
* ascending integers, with a constant interval of time of your choosing
* between those emissions. The first emission is not sent immediately, but
* only after the first period has passed. By default, this operator uses the
* `async` IScheduler to provide a notion of time, but you may pass any
* IScheduler to it.
*
* @example <caption>Emits ascending numbers, one every second (1000ms)</caption>
* var numbers = Rx.Observable.interval(1000);
* numbers.subscribe(x => console.log(x));
*
* @see {@link timer}
* @see {@link delay}
*
* @param {number} [period=0] The interval size in milliseconds (by default)
* or the time unit determined by the scheduler's clock.
* @param {Scheduler} [scheduler=async] The IScheduler to use for scheduling
* the emission of values, and providing a notion of "time".
* @return {Observable} An Observable that emits a sequential number each time
* interval.
* @static true
* @name interval
* @owner Observable
*/
static create(period: number = 0,
scheduler: IScheduler = async): Observable<number> {
return new IntervalObservable(period, scheduler);
}
static dispatch(state: any): void {
const { index, subscriber, period } = state;
subscriber.next(index);
if (subscriber.closed) {
return;
}
state.index += 1;
(<any> this).schedule(state, period);
}
constructor(private period: number = 0,
private scheduler: IScheduler = async) {
super();
if (!isNumeric(period) || period < 0) {
this.period = 0;
}
if (!scheduler || typeof scheduler.schedule !== 'function') {
this.scheduler = async;
}
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<number>) {
const index = 0;
const period = this.period;
const scheduler = this.scheduler;
subscriber.add(scheduler.schedule(IntervalObservable.dispatch, period, {
index, subscriber, period
}));
}
}
+168
View File
@@ -0,0 +1,168 @@
import { root } from '../util/root';
import { IScheduler } from '../Scheduler';
import { Observable } from '../Observable';
import { iterator as Symbol_iterator } from '../symbol/iterator';
import { TeardownLogic } from '../Subscription';
import { Subscriber } from '../Subscriber';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class IteratorObservable<T> extends Observable<T> {
private iterator: any;
static create<T>(iterator: any, scheduler?: IScheduler): IteratorObservable<T> {
return new IteratorObservable(iterator, scheduler);
}
static dispatch(state: any) {
const { index, hasError, iterator, subscriber } = state;
if (hasError) {
subscriber.error(state.error);
return;
}
let result = iterator.next();
if (result.done) {
subscriber.complete();
return;
}
subscriber.next(result.value);
state.index = index + 1;
if (subscriber.closed) {
if (typeof iterator.return === 'function') {
iterator.return();
}
return;
}
(<any> this).schedule(state);
}
constructor(iterator: any, private scheduler?: IScheduler) {
super();
if (iterator == null) {
throw new Error('iterator cannot be null.');
}
this.iterator = getIterator(iterator);
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): TeardownLogic {
let index = 0;
const { iterator, scheduler } = this;
if (scheduler) {
return scheduler.schedule(IteratorObservable.dispatch, 0, {
index, iterator, subscriber
});
} else {
do {
let result = iterator.next();
if (result.done) {
subscriber.complete();
break;
} else {
subscriber.next(result.value);
}
if (subscriber.closed) {
if (typeof iterator.return === 'function') {
iterator.return();
}
break;
}
} while (true);
}
}
}
class StringIterator {
constructor(private str: string,
private idx: number = 0,
private len: number = str.length) {
}
[Symbol_iterator]() { return (this); }
next() {
return this.idx < this.len ? {
done: false,
value: this.str.charAt(this.idx++)
} : {
done: true,
value: undefined
};
}
}
class ArrayIterator {
constructor(private arr: Array<any>,
private idx: number = 0,
private len: number = toLength(arr)) {
}
[Symbol_iterator]() { return this; }
next() {
return this.idx < this.len ? {
done: false,
value: this.arr[this.idx++]
} : {
done: true,
value: undefined
};
}
}
function getIterator(obj: any) {
const i = obj[Symbol_iterator];
if (!i && typeof obj === 'string') {
return new StringIterator(obj);
}
if (!i && obj.length !== undefined) {
return new ArrayIterator(obj);
}
if (!i) {
throw new TypeError('object is not iterable');
}
return obj[Symbol_iterator]();
}
const maxSafeInteger = Math.pow(2, 53) - 1;
function toLength(o: any) {
let len = +o.length;
if (isNaN(len)) {
return 0;
}
if (len === 0 || !numberIsFinite(len)) {
return len;
}
len = sign(len) * Math.floor(Math.abs(len));
if (len <= 0) {
return 0;
}
if (len > maxSafeInteger) {
return maxSafeInteger;
}
return len;
}
function numberIsFinite(value: any) {
return typeof value === 'number' && root.isFinite(value);
}
function sign(value: any) {
let valueAsNumber = +value;
if (valueAsNumber === 0) {
return valueAsNumber;
}
if (isNaN(valueAsNumber)) {
return valueAsNumber;
}
return valueAsNumber < 0 ? -1 : 1;
}
+53
View File
@@ -0,0 +1,53 @@
import { Observable } from '../Observable';
import { Subscriber } from '../Subscriber';
import { noop } from '../util/noop';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class NeverObservable<T> extends Observable<T> {
/**
* Creates an Observable that emits no items to the Observer.
*
* <span class="informal">An Observable that never emits anything.</span>
*
* <img src="./img/never.png" width="100%">
*
* This static operator is useful for creating a simple Observable that emits
* neither values nor errors nor the completion notification. It can be used
* for testing purposes or for composing with other Observables. Please note
* that by never emitting a complete notification, this Observable keeps the
* subscription from being disposed automatically. Subscriptions need to be
* manually disposed.
*
* @example <caption>Emit the number 7, then never emit anything else (not even complete).</caption>
* function info() {
* console.log('Will not be called');
* }
* var result = Rx.Observable.never().startWith(7);
* result.subscribe(x => console.log(x), info, info);
*
* @see {@link create}
* @see {@link empty}
* @see {@link of}
* @see {@link throw}
*
* @return {Observable} A "never" Observable: never emits anything.
* @static true
* @name never
* @owner Observable
*/
static create<T>() {
return new NeverObservable<T>();
}
constructor() {
super();
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): void {
noop();
}
}
+95
View File
@@ -0,0 +1,95 @@
import { IScheduler } from '../Scheduler';
import { Action } from '../scheduler/Action';
import { Observable } from '../Observable';
import { Subscriber } from '../Subscriber';
import { TeardownLogic } from '../Subscription';
interface PairsContext<T> {
obj: Object;
keys: Array<string>;
length: number;
index: number;
subscriber: Subscriber<Array<string | T>>;
}
function dispatch<T>(this: Action<PairsContext<T>>, state: PairsContext<T>) {
const {obj, keys, length, index, subscriber} = state;
if (index === length) {
subscriber.complete();
return;
}
const key = keys[index];
subscriber.next([key, obj[key]]);
state.index = index + 1;
this.schedule(state);
}
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class PairsObservable<T> extends Observable<Array<string | T>> {
private keys: Array<string>;
/**
* Convert an object into an observable sequence of [key, value] pairs
* using an optional IScheduler to enumerate the object.
*
* @example <caption>Converts a javascript object to an Observable</caption>
* var obj = {
* foo: 42,
* bar: 56,
* baz: 78
* };
*
* var source = Rx.Observable.pairs(obj);
*
* var subscription = source.subscribe(
* function (x) {
* console.log('Next: %s', x);
* },
* function (err) {
* console.log('Error: %s', err);
* },
* function () {
* console.log('Completed');
* });
*
* @param {Object} obj The object to inspect and turn into an
* Observable sequence.
* @param {Scheduler} [scheduler] An optional IScheduler to run the
* enumeration of the input sequence on.
* @returns {(Observable<Array<string | T>>)} An observable sequence of
* [key, value] pairs from the object.
*/
static create<T>(obj: Object, scheduler?: IScheduler): Observable<Array<string | T>> {
return new PairsObservable<T>(obj, scheduler);
}
constructor(private obj: Object, private scheduler?: IScheduler) {
super();
this.keys = Object.keys(obj);
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<Array<string | T>>): TeardownLogic {
const {keys, scheduler} = this;
const length = keys.length;
if (scheduler) {
return scheduler.schedule(dispatch, 0, {
obj: this.obj, keys, length, index: 0, subscriber
});
} else {
for (let idx = 0; idx < length; idx++) {
const key = keys[idx];
subscriber.next([key, this.obj[key]]);
}
subscriber.complete();
}
}
}
+130
View File
@@ -0,0 +1,130 @@
import { root } from '../util/root';
import { IScheduler } from '../Scheduler';
import { Observable } from '../Observable';
import { Subscriber } from '../Subscriber';
import { TeardownLogic } from '../Subscription';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class PromiseObservable<T> extends Observable<T> {
public value: T;
/**
* Converts a Promise to an Observable.
*
* <span class="informal">Returns an Observable that just emits the Promise's
* resolved value, then completes.</span>
*
* Converts an ES2015 Promise or a Promises/A+ spec compliant Promise to an
* Observable. If the Promise resolves with a value, the output Observable
* emits that resolved value as a `next`, and then completes. If the Promise
* is rejected, then the output Observable emits the corresponding Error.
*
* @example <caption>Convert the Promise returned by Fetch to an Observable</caption>
* var result = Rx.Observable.fromPromise(fetch('http://myserver.com/'));
* result.subscribe(x => console.log(x), e => console.error(e));
*
* @see {@link bindCallback}
* @see {@link from}
*
* @param {PromiseLike<T>} promise The promise to be converted.
* @param {Scheduler} [scheduler] An optional IScheduler to use for scheduling
* the delivery of the resolved value (or the rejection).
* @return {Observable<T>} An Observable which wraps the Promise.
* @static true
* @name fromPromise
* @owner Observable
*/
static create<T>(promise: PromiseLike<T>, scheduler?: IScheduler): Observable<T> {
return new PromiseObservable(promise, scheduler);
}
constructor(private promise: PromiseLike<T>, private scheduler?: IScheduler) {
super();
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): TeardownLogic {
const promise = this.promise;
const scheduler = this.scheduler;
if (scheduler == null) {
if (this._isScalar) {
if (!subscriber.closed) {
subscriber.next(this.value);
subscriber.complete();
}
} else {
promise.then(
(value) => {
this.value = value;
this._isScalar = true;
if (!subscriber.closed) {
subscriber.next(value);
subscriber.complete();
}
},
(err) => {
if (!subscriber.closed) {
subscriber.error(err);
}
}
)
.then(null, err => {
// escape the promise trap, throw unhandled errors
root.setTimeout(() => { throw err; });
});
}
} else {
if (this._isScalar) {
if (!subscriber.closed) {
return scheduler.schedule(dispatchNext, 0, { value: this.value, subscriber });
}
} else {
promise.then(
(value) => {
this.value = value;
this._isScalar = true;
if (!subscriber.closed) {
subscriber.add(scheduler.schedule(dispatchNext, 0, { value, subscriber }));
}
},
(err) => {
if (!subscriber.closed) {
subscriber.add(scheduler.schedule(dispatchError, 0, { err, subscriber }));
}
})
.then(null, (err) => {
// escape the promise trap, throw unhandled errors
root.setTimeout(() => { throw err; });
});
}
}
}
}
interface DispatchNextArg<T> {
subscriber: Subscriber<T>;
value: T;
}
function dispatchNext<T>(arg: DispatchNextArg<T>) {
const { value, subscriber } = arg;
if (!subscriber.closed) {
subscriber.next(value);
subscriber.complete();
}
}
interface DispatchErrorArg<T> {
subscriber: Subscriber<T>;
err: any;
}
function dispatchError<T>(arg: DispatchErrorArg<T>) {
const { err, subscriber } = arg;
if (!subscriber.closed) {
subscriber.error(err);
}
}
+106
View File
@@ -0,0 +1,106 @@
import { IScheduler } from '../Scheduler';
import { Observable } from '../Observable';
import { TeardownLogic } from '../Subscription';
import { Subscriber } from '../Subscriber';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class RangeObservable extends Observable<number> {
/**
* Creates an Observable that emits a sequence of numbers within a specified
* range.
*
* <span class="informal">Emits a sequence of numbers in a range.</span>
*
* <img src="./img/range.png" width="100%">
*
* `range` operator emits a range of sequential integers, in order, where you
* select the `start` of the range and its `length`. By default, uses no
* IScheduler and just delivers the notifications synchronously, but may use
* an optional IScheduler to regulate those deliveries.
*
* @example <caption>Emits the numbers 1 to 10</caption>
* var numbers = Rx.Observable.range(1, 10);
* numbers.subscribe(x => console.log(x));
*
* @see {@link timer}
* @see {@link interval}
*
* @param {number} [start=0] The value of the first integer in the sequence.
* @param {number} [count=0] The number of sequential integers to generate.
* @param {Scheduler} [scheduler] A {@link IScheduler} to use for scheduling
* the emissions of the notifications.
* @return {Observable} An Observable of numbers that emits a finite range of
* sequential integers.
* @static true
* @name range
* @owner Observable
*/
static create(start: number = 0,
count: number = 0,
scheduler?: IScheduler): Observable<number> {
return new RangeObservable(start, count, scheduler);
}
static dispatch(state: any) {
const { start, index, count, subscriber } = state;
if (index >= count) {
subscriber.complete();
return;
}
subscriber.next(start);
if (subscriber.closed) {
return;
}
state.index = index + 1;
state.start = start + 1;
(<any> this).schedule(state);
}
private start: number;
private _count: number;
private scheduler: IScheduler;
constructor(start: number,
count: number,
scheduler?: IScheduler) {
super();
this.start = start;
this._count = count;
this.scheduler = scheduler;
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<number>): TeardownLogic {
let index = 0;
let start = this.start;
const count = this._count;
const scheduler = this.scheduler;
if (scheduler) {
return scheduler.schedule(RangeObservable.dispatch, 0, {
index, count, start, subscriber
});
} else {
do {
if (index++ >= count) {
subscriber.complete();
break;
}
subscriber.next(start++);
if (subscriber.closed) {
break;
}
} while (true);
}
}
}
+57
View File
@@ -0,0 +1,57 @@
import { IScheduler } from '../Scheduler';
import { Observable } from '../Observable';
import { Subscriber } from '../Subscriber';
import { TeardownLogic } from '../Subscription';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class ScalarObservable<T> extends Observable<T> {
static create<T>(value: T, scheduler?: IScheduler): ScalarObservable<T> {
return new ScalarObservable(value, scheduler);
}
static dispatch(state: any): void {
const { done, value, subscriber } = state;
if (done) {
subscriber.complete();
return;
}
subscriber.next(value);
if (subscriber.closed) {
return;
}
state.done = true;
(<any> this).schedule(state);
}
_isScalar: boolean = true;
constructor(public value: T, private scheduler?: IScheduler) {
super();
if (scheduler) {
this._isScalar = false;
}
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): TeardownLogic {
const value = this.value;
const scheduler = this.scheduler;
if (scheduler) {
return scheduler.schedule(ScalarObservable.dispatch, 0, {
done: false, value, subscriber
});
} else {
subscriber.next(value);
if (!subscriber.closed) {
subscriber.complete();
}
}
}
}
@@ -0,0 +1,50 @@
import { Action } from '../scheduler/Action';
import { IScheduler } from '../Scheduler';
import { Subscriber } from '../Subscriber';
import { Subscription } from '../Subscription';
import { Observable } from '../Observable';
import { asap } from '../scheduler/asap';
import { isNumeric } from '../util/isNumeric';
export interface DispatchArg<T> {
source: Observable<T>;
subscriber: Subscriber<T>;
}
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class SubscribeOnObservable<T> extends Observable<T> {
static create<T>(source: Observable<T>, delay: number = 0, scheduler: IScheduler = asap): Observable<T> {
return new SubscribeOnObservable(source, delay, scheduler);
}
static dispatch<T>(this: Action<T>, arg: DispatchArg<T>): Subscription {
const { source, subscriber } = arg;
return this.add(source.subscribe(subscriber));
}
constructor(public source: Observable<T>,
private delayTime: number = 0,
private scheduler: IScheduler = asap) {
super();
if (!isNumeric(delayTime) || delayTime < 0) {
this.delayTime = 0;
}
if (!scheduler || typeof scheduler.schedule !== 'function') {
this.scheduler = asap;
}
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>) {
const delay = this.delayTime;
const source = this.source;
const scheduler = this.scheduler;
return scheduler.schedule(SubscribeOnObservable.dispatch, delay, {
source, subscriber
});
}
}
+115
View File
@@ -0,0 +1,115 @@
import { isNumeric } from '../util/isNumeric';
import { IScheduler } from '../Scheduler';
import { Observable } from '../Observable';
import { async } from '../scheduler/async';
import { isScheduler } from '../util/isScheduler';
import { isDate } from '../util/isDate';
import { TeardownLogic } from '../Subscription';
import { Subscriber } from '../Subscriber';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class TimerObservable extends Observable<number> {
/**
* Creates an Observable that starts emitting after an `initialDelay` and
* emits ever increasing numbers after each `period` of time thereafter.
*
* <span class="informal">Its like {@link interval}, but you can specify when
* should the emissions start.</span>
*
* <img src="./img/timer.png" width="100%">
*
* `timer` returns an Observable that emits an infinite sequence of ascending
* integers, with a constant interval of time, `period` of your choosing
* between those emissions. The first emission happens after the specified
* `initialDelay`. The initial delay may be a {@link Date}. By default, this
* operator uses the `async` IScheduler to provide a notion of time, but you
* may pass any IScheduler to it. If `period` is not specified, the output
* Observable emits only one value, `0`. Otherwise, it emits an infinite
* sequence.
*
* @example <caption>Emits ascending numbers, one every second (1000ms), starting after 3 seconds</caption>
* var numbers = Rx.Observable.timer(3000, 1000);
* numbers.subscribe(x => console.log(x));
*
* @example <caption>Emits one number after five seconds</caption>
* var numbers = Rx.Observable.timer(5000);
* numbers.subscribe(x => console.log(x));
*
* @see {@link interval}
* @see {@link delay}
*
* @param {number|Date} initialDelay The initial delay time to wait before
* emitting the first value of `0`.
* @param {number} [period] The period of time between emissions of the
* subsequent numbers.
* @param {Scheduler} [scheduler=async] The IScheduler to use for scheduling
* the emission of values, and providing a notion of "time".
* @return {Observable} An Observable that emits a `0` after the
* `initialDelay` and ever increasing numbers after each `period` of time
* thereafter.
* @static true
* @name timer
* @owner Observable
*/
static create(initialDelay: number | Date = 0,
period?: number | IScheduler,
scheduler?: IScheduler): Observable<number> {
return new TimerObservable(initialDelay, period, scheduler);
}
static dispatch(state: any) {
const { index, period, subscriber } = state;
const action = (<any> this);
subscriber.next(index);
if (subscriber.closed) {
return;
} else if (period === -1) {
return subscriber.complete();
}
state.index = index + 1;
action.schedule(state, period);
}
private period: number = -1;
private dueTime: number = 0;
private scheduler: IScheduler;
constructor(dueTime: number | Date = 0,
period?: number | IScheduler,
scheduler?: IScheduler) {
super();
if (isNumeric(period)) {
this.period = Number(period) < 1 && 1 || Number(period);
} else if (isScheduler(period)) {
scheduler = <IScheduler> period;
}
if (!isScheduler(scheduler)) {
scheduler = async;
}
this.scheduler = scheduler;
this.dueTime = isDate(dueTime) ?
(+dueTime - this.scheduler.now()) :
(<number> dueTime);
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<number>): TeardownLogic {
const index = 0;
const { period, dueTime, scheduler } = this;
return scheduler.schedule(TimerObservable.dispatch, dueTime, {
index, period, subscriber
});
}
}
+57
View File
@@ -0,0 +1,57 @@
import { Observable, SubscribableOrPromise } from '../Observable';
import { Subscriber } from '../Subscriber';
import { AnonymousSubscription, TeardownLogic } from '../Subscription';
import { subscribeToResult } from '../util/subscribeToResult';
import { OuterSubscriber } from '../OuterSubscriber';
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class UsingObservable<T> extends Observable<T> {
static create<T>(resourceFactory: () => AnonymousSubscription | void,
observableFactory: (resource: AnonymousSubscription) => SubscribableOrPromise<T> | void): Observable<T> {
return new UsingObservable<T>(resourceFactory, observableFactory);
}
constructor(private resourceFactory: () => AnonymousSubscription | void,
private observableFactory: (resource: AnonymousSubscription) => SubscribableOrPromise<T> | void) {
super();
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): TeardownLogic {
const { resourceFactory, observableFactory } = this;
let resource: AnonymousSubscription;
try {
resource = <AnonymousSubscription>resourceFactory();
return new UsingSubscriber(subscriber, resource, observableFactory);
} catch (err) {
subscriber.error(err);
}
}
}
class UsingSubscriber<T> extends OuterSubscriber<T, T> {
constructor(destination: Subscriber<T>,
private resource: AnonymousSubscription,
private observableFactory: (resource: AnonymousSubscription) => SubscribableOrPromise<T> | void) {
super(destination);
destination.add(resource);
this.tryUse();
}
private tryUse(): void {
try {
const source = this.observableFactory.call(this, this.resource);
if (source) {
this.add(subscribeToResult(this, source));
}
} catch (err) {
this._error(err);
}
}
}
+3
View File
@@ -0,0 +1,3 @@
import { BoundCallbackObservable } from './BoundCallbackObservable';
export const bindCallback = BoundCallbackObservable.create;
+3
View File
@@ -0,0 +1,3 @@
import { BoundNodeCallbackObservable } from './BoundNodeCallbackObservable';
export const bindNodeCallback = BoundNodeCallbackObservable.create;
+161
View File
@@ -0,0 +1,161 @@
import { Observable, ObservableInput } from '../Observable';
import { IScheduler } from '../Scheduler';
import { isScheduler } from '../util/isScheduler';
import { isArray } from '../util/isArray';
import { ArrayObservable } from './ArrayObservable';
import { CombineLatestOperator } from '../operators/combineLatest';
/* tslint:disable:max-line-length */
export function combineLatest<T, R>(v1: ObservableInput<T>, project: (v1: T) => R, scheduler?: IScheduler): Observable<R>;
export function combineLatest<T, T2, R>(v1: ObservableInput<T>, v2: ObservableInput<T2>, project: (v1: T, v2: T2) => R, scheduler?: IScheduler): Observable<R>;
export function combineLatest<T, T2, T3, R>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, project: (v1: T, v2: T2, v3: T3) => R, scheduler?: IScheduler): Observable<R>;
export function combineLatest<T, T2, T3, T4, R>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, project: (v1: T, v2: T2, v3: T3, v4: T4) => R, scheduler?: IScheduler): Observable<R>;
export function combineLatest<T, T2, T3, T4, T5, R>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, v5: ObservableInput<T5>, project: (v1: T, v2: T2, v3: T3, v4: T4, v5: T5) => R, scheduler?: IScheduler): Observable<R>;
export function combineLatest<T, T2, T3, T4, T5, T6, R>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, v5: ObservableInput<T5>, v6: ObservableInput<T6>, project: (v1: T, v2: T2, v3: T3, v4: T4, v5: T5, v6: T6) => R, scheduler?: IScheduler): Observable<R>;
export function combineLatest<T, T2>(v1: ObservableInput<T>, v2: ObservableInput<T2>, scheduler?: IScheduler): Observable<[T, T2]>;
export function combineLatest<T, T2, T3>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, scheduler?: IScheduler): Observable<[T, T2, T3]>;
export function combineLatest<T, T2, T3, T4>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, scheduler?: IScheduler): Observable<[T, T2, T3, T4]>;
export function combineLatest<T, T2, T3, T4, T5>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, v5: ObservableInput<T5>, scheduler?: IScheduler): Observable<[T, T2, T3, T4, T5]>;
export function combineLatest<T, T2, T3, T4, T5, T6>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, v5: ObservableInput<T5>, v6: ObservableInput<T6>, scheduler?: IScheduler): Observable<[T, T2, T3, T4, T5, T6]>;
export function combineLatest<T>(array: ObservableInput<T>[], scheduler?: IScheduler): Observable<T[]>;
export function combineLatest<R>(array: ObservableInput<any>[], scheduler?: IScheduler): Observable<R>;
export function combineLatest<T, R>(array: ObservableInput<T>[], project: (...values: Array<T>) => R, scheduler?: IScheduler): Observable<R>;
export function combineLatest<R>(array: ObservableInput<any>[], project: (...values: Array<any>) => R, scheduler?: IScheduler): Observable<R>;
export function combineLatest<T>(...observables: Array<ObservableInput<T> | IScheduler>): Observable<T[]>;
export function combineLatest<T, R>(...observables: Array<ObservableInput<T> | ((...values: Array<T>) => R) | IScheduler>): Observable<R>;
export function combineLatest<R>(...observables: Array<ObservableInput<any> | ((...values: Array<any>) => R) | IScheduler>): Observable<R>;
/* tslint:enable:max-line-length */
/**
* Combines multiple Observables to create an Observable whose values are
* calculated from the latest values of each of its input Observables.
*
* <span class="informal">Whenever any input Observable emits a value, it
* computes a formula using the latest values from all the inputs, then emits
* the output of that formula.</span>
*
* <img src="./img/combineLatest.png" width="100%">
*
* `combineLatest` combines the values from all the Observables passed as
* arguments. This is done by subscribing to each Observable in order and,
* whenever any Observable emits, collecting an array of the most recent
* values from each Observable. So if you pass `n` Observables to operator,
* returned Observable will always emit an array of `n` values, in order
* corresponding to order of passed Observables (value from the first Observable
* on the first place and so on).
*
* Static version of `combineLatest` accepts either an array of Observables
* or each Observable can be put directly as an argument. Note that array of
* Observables is good choice, if you don't know beforehand how many Observables
* you will combine. Passing empty array will result in Observable that
* completes immediately.
*
* To ensure output array has always the same length, `combineLatest` will
* actually wait for all input Observables to emit at least once,
* before it starts emitting results. This means if some Observable emits
* values before other Observables started emitting, all that values but last
* will be lost. On the other hand, is some Observable does not emit value but
* completes, resulting Observable will complete at the same moment without
* emitting anything, since it will be now impossible to include value from
* completed Observable in resulting array. Also, if some input Observable does
* not emit any value and never completes, `combineLatest` will also never emit
* and never complete, since, again, it will wait for all streams to emit some
* value.
*
* If at least one Observable was passed to `combineLatest` and all passed Observables
* emitted something, resulting Observable will complete when all combined
* streams complete. So even if some Observable completes, result of
* `combineLatest` will still emit values when other Observables do. In case
* of completed Observable, its value from now on will always be the last
* emitted value. On the other hand, if any Observable errors, `combineLatest`
* will error immediately as well, and all other Observables will be unsubscribed.
*
* `combineLatest` accepts as optional parameter `project` function, which takes
* as arguments all values that would normally be emitted by resulting Observable.
* `project` can return any kind of value, which will be then emitted by Observable
* instead of default array. Note that `project` does not take as argument that array
* of values, but values themselves. That means default `project` can be imagined
* as function that takes all its arguments and puts them into an array.
*
*
* @example <caption>Combine two timer Observables</caption>
* const firstTimer = Rx.Observable.timer(0, 1000); // emit 0, 1, 2... after every second, starting from now
* const secondTimer = Rx.Observable.timer(500, 1000); // emit 0, 1, 2... after every second, starting 0,5s from now
* const combinedTimers = Rx.Observable.combineLatest(firstTimer, secondTimer);
* combinedTimers.subscribe(value => console.log(value));
* // Logs
* // [0, 0] after 0.5s
* // [1, 0] after 1s
* // [1, 1] after 1.5s
* // [2, 1] after 2s
*
*
* @example <caption>Combine an array of Observables</caption>
* const observables = [1, 5, 10].map(
* n => Rx.Observable.of(n).delay(n * 1000).startWith(0) // emit 0 and then emit n after n seconds
* );
* const combined = Rx.Observable.combineLatest(observables);
* combined.subscribe(value => console.log(value));
* // Logs
* // [0, 0, 0] immediately
* // [1, 0, 0] after 1s
* // [1, 5, 0] after 5s
* // [1, 5, 10] after 10s
*
*
* @example <caption>Use project function to dynamically calculate the Body-Mass Index</caption>
* var weight = Rx.Observable.of(70, 72, 76, 79, 75);
* var height = Rx.Observable.of(1.76, 1.77, 1.78);
* var bmi = Rx.Observable.combineLatest(weight, height, (w, h) => w / (h * h));
* bmi.subscribe(x => console.log('BMI is ' + x));
*
* // With output to console:
* // BMI is 24.212293388429753
* // BMI is 23.93948099205209
* // BMI is 23.671253629592222
*
*
* @see {@link combineAll}
* @see {@link merge}
* @see {@link withLatestFrom}
*
* @param {ObservableInput} observable1 An input Observable to combine with other Observables.
* @param {ObservableInput} observable2 An input Observable to combine with other Observables.
* More than one input Observables may be given as arguments
* or an array of Observables may be given as the first argument.
* @param {function} [project] An optional function to project the values from
* the combined latest values into a new value on the output Observable.
* @param {Scheduler} [scheduler=null] The IScheduler to use for subscribing to
* each input Observable.
* @return {Observable} An Observable of projected values from the most recent
* values from each input Observable, or an array of the most recent values from
* each input Observable.
* @static true
* @name combineLatest
* @owner Observable
*/
export function combineLatest<T, R>(...observables: Array<any | ObservableInput<any> |
Array<ObservableInput<any>> |
(((...values: Array<any>) => R)) |
IScheduler>): Observable<R> {
let project: (...values: Array<any>) => R = null;
let scheduler: IScheduler = null;
if (isScheduler(observables[observables.length - 1])) {
scheduler = <IScheduler>observables.pop();
}
if (typeof observables[observables.length - 1] === 'function') {
project = <(...values: Array<any>) => R>observables.pop();
}
// if the first and only other argument besides the resultSelector is an array
// assume it's been called with `combineLatest([obs1, obs2, obs3], project)`
if (observables.length === 1 && isArray(observables[0])) {
observables = <Array<Observable<any>>>observables[0];
}
return new ArrayObservable(observables, scheduler).lift(new CombineLatestOperator<T, R>(project));
}
+116
View File
@@ -0,0 +1,116 @@
import { Observable, ObservableInput } from '../Observable';
import { IScheduler } from '../Scheduler';
import { isScheduler } from '../util/isScheduler';
import { of } from './of';
import { from } from './from';
import { concatAll } from '../operators/concatAll';
/* tslint:disable:max-line-length */
export function concat<T>(v1: ObservableInput<T>, scheduler?: IScheduler): Observable<T>;
export function concat<T, T2>(v1: ObservableInput<T>, v2: ObservableInput<T2>, scheduler?: IScheduler): Observable<T | T2>;
export function concat<T, T2, T3>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, scheduler?: IScheduler): Observable<T | T2 | T3>;
export function concat<T, T2, T3, T4>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, scheduler?: IScheduler): Observable<T | T2 | T3 | T4>;
export function concat<T, T2, T3, T4, T5>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, v5: ObservableInput<T5>, scheduler?: IScheduler): Observable<T | T2 | T3 | T4 | T5>;
export function concat<T, T2, T3, T4, T5, T6>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, v5: ObservableInput<T5>, v6: ObservableInput<T6>, scheduler?: IScheduler): Observable<T | T2 | T3 | T4 | T5 | T6>;
export function concat<T>(...observables: (ObservableInput<T> | IScheduler)[]): Observable<T>;
export function concat<T, R>(...observables: (ObservableInput<any> | IScheduler)[]): Observable<R>;
/* tslint:enable:max-line-length */
/**
* Creates an output Observable which sequentially emits all values from given
* Observable and then moves on to the next.
*
* <span class="informal">Concatenates multiple Observables together by
* sequentially emitting their values, one Observable after the other.</span>
*
* <img src="./img/concat.png" width="100%">
*
* `concat` joins multiple Observables together, by subscribing to them one at a time and
* merging their results into the output Observable. You can pass either an array of
* Observables, or put them directly as arguments. Passing an empty array will result
* in Observable that completes immediately.
*
* `concat` will subscribe to first input Observable and emit all its values, without
* changing or affecting them in any way. When that Observable completes, it will
* subscribe to then next Observable passed and, again, emit its values. This will be
* repeated, until the operator runs out of Observables. When last input Observable completes,
* `concat` will complete as well. At any given moment only one Observable passed to operator
* emits values. If you would like to emit values from passed Observables concurrently, check out
* {@link merge} instead, especially with optional `concurrent` parameter. As a matter of fact,
* `concat` is an equivalent of `merge` operator with `concurrent` parameter set to `1`.
*
* Note that if some input Observable never completes, `concat` will also never complete
* and Observables following the one that did not complete will never be subscribed. On the other
* hand, if some Observable simply completes immediately after it is subscribed, it will be
* invisible for `concat`, which will just move on to the next Observable.
*
* If any Observable in chain errors, instead of passing control to the next Observable,
* `concat` will error immediately as well. Observables that would be subscribed after
* the one that emitted error, never will.
*
* If you pass to `concat` the same Observable many times, its stream of values
* will be "replayed" on every subscription, which means you can repeat given Observable
* as many times as you like. If passing the same Observable to `concat` 1000 times becomes tedious,
* you can always use {@link repeat}.
*
* @example <caption>Concatenate a timer counting from 0 to 3 with a synchronous sequence from 1 to 10</caption>
* var timer = Rx.Observable.interval(1000).take(4);
* var sequence = Rx.Observable.range(1, 10);
* var result = Rx.Observable.concat(timer, sequence);
* result.subscribe(x => console.log(x));
*
* // results in:
* // 0 -1000ms-> 1 -1000ms-> 2 -1000ms-> 3 -immediate-> 1 ... 10
*
*
* @example <caption>Concatenate an array of 3 Observables</caption>
* var timer1 = Rx.Observable.interval(1000).take(10);
* var timer2 = Rx.Observable.interval(2000).take(6);
* var timer3 = Rx.Observable.interval(500).take(10);
* var result = Rx.Observable.concat([timer1, timer2, timer3]); // note that array is passed
* result.subscribe(x => console.log(x));
*
* // results in the following:
* // (Prints to console sequentially)
* // -1000ms-> 0 -1000ms-> 1 -1000ms-> ... 9
* // -2000ms-> 0 -2000ms-> 1 -2000ms-> ... 5
* // -500ms-> 0 -500ms-> 1 -500ms-> ... 9
*
*
* @example <caption>Concatenate the same Observable to repeat it</caption>
* const timer = Rx.Observable.interval(1000).take(2);
*
* Rx.Observable.concat(timer, timer) // concating the same Observable!
* .subscribe(
* value => console.log(value),
* err => {},
* () => console.log('...and it is done!')
* );
*
* // Logs:
* // 0 after 1s
* // 1 after 2s
* // 0 after 3s
* // 1 after 4s
* // "...and it is done!" also after 4s
*
* @see {@link concatAll}
* @see {@link concatMap}
* @see {@link concatMapTo}
*
* @param {ObservableInput} input1 An input Observable to concatenate with others.
* @param {ObservableInput} input2 An input Observable to concatenate with others.
* More than one input Observables may be given as argument.
* @param {Scheduler} [scheduler=null] An optional IScheduler to schedule each
* Observable subscription on.
* @return {Observable} All values of each passed Observable merged into a
* single Observable, in order, in serial fashion.
* @static true
* @name concat
* @owner Observable
*/
export function concat<T, R>(...observables: Array<ObservableInput<any> | IScheduler>): Observable<R> {
if (observables.length === 1 || (observables.length === 2 && isScheduler(observables[1]))) {
return from(<any>observables[0]);
}
return concatAll()(of(...observables)) as Observable<R>;
}
+3
View File
@@ -0,0 +1,3 @@
import { DeferObservable } from './DeferObservable';
export const defer = DeferObservable.create;
+488
View File
@@ -0,0 +1,488 @@
import { root } from '../../util/root';
import { tryCatch } from '../../util/tryCatch';
import { errorObject } from '../../util/errorObject';
import { Observable } from '../../Observable';
import { Subscriber } from '../../Subscriber';
import { TeardownLogic } from '../../Subscription';
import { map } from '../../operators/map';
export interface AjaxRequest {
url?: string;
body?: any;
user?: string;
async?: boolean;
method?: string;
headers?: Object;
timeout?: number;
password?: string;
hasContent?: boolean;
crossDomain?: boolean;
withCredentials?: boolean;
createXHR?: () => XMLHttpRequest;
progressSubscriber?: Subscriber<any>;
responseType?: string;
}
function getCORSRequest(this: AjaxRequest): XMLHttpRequest {
if (root.XMLHttpRequest) {
return new root.XMLHttpRequest();
} else if (!!root.XDomainRequest) {
return new root.XDomainRequest();
} else {
throw new Error('CORS is not supported by your browser');
}
}
function getXMLHttpRequest(): XMLHttpRequest {
if (root.XMLHttpRequest) {
return new root.XMLHttpRequest();
} else {
let progId: string;
try {
const progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'];
for (let i = 0; i < 3; i++) {
try {
progId = progIds[i];
if (new root.ActiveXObject(progId)) {
break;
}
} catch (e) {
//suppress exceptions
}
}
return new root.ActiveXObject(progId);
} catch (e) {
throw new Error('XMLHttpRequest is not supported by your browser');
}
}
}
export interface AjaxCreationMethod {
(urlOrRequest: string | AjaxRequest): Observable<AjaxResponse>;
get(url: string, headers?: Object): Observable<AjaxResponse>;
post(url: string, body?: any, headers?: Object): Observable<AjaxResponse>;
put(url: string, body?: any, headers?: Object): Observable<AjaxResponse>;
patch(url: string, body?: any, headers?: Object): Observable<AjaxResponse>;
delete(url: string, headers?: Object): Observable<AjaxResponse>;
getJSON<T>(url: string, headers?: Object): Observable<T>;
}
export function ajaxGet(url: string, headers: Object = null) {
return new AjaxObservable<AjaxResponse>({ method: 'GET', url, headers });
};
export function ajaxPost(url: string, body?: any, headers?: Object): Observable<AjaxResponse> {
return new AjaxObservable<AjaxResponse>({ method: 'POST', url, body, headers });
};
export function ajaxDelete(url: string, headers?: Object): Observable<AjaxResponse> {
return new AjaxObservable<AjaxResponse>({ method: 'DELETE', url, headers });
};
export function ajaxPut(url: string, body?: any, headers?: Object): Observable<AjaxResponse> {
return new AjaxObservable<AjaxResponse>({ method: 'PUT', url, body, headers });
};
export function ajaxPatch(url: string, body?: any, headers?: Object): Observable<AjaxResponse> {
return new AjaxObservable<AjaxResponse>({ method: 'PATCH', url, body, headers });
};
const mapResponse = map((x: AjaxResponse, index: number) => x.response);
export function ajaxGetJSON<T>(url: string, headers?: Object): Observable<T> {
return mapResponse(
new AjaxObservable<AjaxResponse>({
method: 'GET',
url,
responseType: 'json',
headers
})
);
};
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class AjaxObservable<T> extends Observable<T> {
/**
* Creates an observable for an Ajax request with either a request object with
* url, headers, etc or a string for a URL.
*
* @example
* source = Rx.Observable.ajax('/products');
* source = Rx.Observable.ajax({ url: 'products', method: 'GET' });
*
* @param {string|Object} request Can be one of the following:
* A string of the URL to make the Ajax call.
* An object with the following properties
* - url: URL of the request
* - body: The body of the request
* - method: Method of the request, such as GET, POST, PUT, PATCH, DELETE
* - async: Whether the request is async
* - headers: Optional headers
* - crossDomain: true if a cross domain request, else false
* - createXHR: a function to override if you need to use an alternate
* XMLHttpRequest implementation.
* - resultSelector: a function to use to alter the output value type of
* the Observable. Gets {@link AjaxResponse} as an argument.
* @return {Observable} An observable sequence containing the XMLHttpRequest.
* @static true
* @name ajax
* @owner Observable
*/
static create: AjaxCreationMethod = (() => {
const create: any = (urlOrRequest: string | AjaxRequest) => {
return new AjaxObservable(urlOrRequest);
};
create.get = ajaxGet;
create.post = ajaxPost;
create.delete = ajaxDelete;
create.put = ajaxPut;
create.patch = ajaxPatch;
create.getJSON = ajaxGetJSON;
return <AjaxCreationMethod>create;
})();
private request: AjaxRequest;
constructor(urlOrRequest: string | AjaxRequest) {
super();
const request: AjaxRequest = {
async: true,
createXHR: function(this: AjaxRequest) {
return this.crossDomain ? getCORSRequest.call(this) : getXMLHttpRequest();
},
crossDomain: false,
withCredentials: false,
headers: {},
method: 'GET',
responseType: 'json',
timeout: 0
};
if (typeof urlOrRequest === 'string') {
request.url = urlOrRequest;
} else {
for (const prop in urlOrRequest) {
if (urlOrRequest.hasOwnProperty(prop)) {
request[prop] = urlOrRequest[prop];
}
}
}
this.request = request;
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): TeardownLogic {
return new AjaxSubscriber(subscriber, this.request);
}
}
/**
* We need this JSDoc comment for affecting ESDoc.
* @ignore
* @extends {Ignored}
*/
export class AjaxSubscriber<T> extends Subscriber<Event> {
private xhr: XMLHttpRequest;
private done: boolean = false;
constructor(destination: Subscriber<T>, public request: AjaxRequest) {
super(destination);
const headers = request.headers = request.headers || {};
// force CORS if requested
if (!request.crossDomain && !headers['X-Requested-With']) {
headers['X-Requested-With'] = 'XMLHttpRequest';
}
// ensure content type is set
if (!('Content-Type' in headers) && !(root.FormData && request.body instanceof root.FormData) && typeof request.body !== 'undefined') {
headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8';
}
// properly serialize body
request.body = this.serializeBody(request.body, request.headers['Content-Type']);
this.send();
}
next(e: Event): void {
this.done = true;
const { xhr, request, destination } = this;
const response = new AjaxResponse(e, xhr, request);
destination.next(response);
}
private send(): XMLHttpRequest {
const {
request,
request: { user, method, url, async, password, headers, body }
} = this;
const createXHR = request.createXHR;
const xhr: XMLHttpRequest = tryCatch(createXHR).call(request);
if (<any>xhr === errorObject) {
this.error(errorObject.e);
} else {
this.xhr = xhr;
// set up the events before open XHR
// https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
// You need to add the event listeners before calling open() on the request.
// Otherwise the progress events will not fire.
this.setupEvents(xhr, request);
// open XHR
let result: any;
if (user) {
result = tryCatch(xhr.open).call(xhr, method, url, async, user, password);
} else {
result = tryCatch(xhr.open).call(xhr, method, url, async);
}
if (result === errorObject) {
this.error(errorObject.e);
return null;
}
// timeout, responseType and withCredentials can be set once the XHR is open
if (async) {
xhr.timeout = request.timeout;
xhr.responseType = request.responseType as any;
}
if ('withCredentials' in xhr) {
xhr.withCredentials = !!request.withCredentials;
}
// set headers
this.setHeaders(xhr, headers);
// finally send the request
result = body ? tryCatch(xhr.send).call(xhr, body) : tryCatch(xhr.send).call(xhr);
if (result === errorObject) {
this.error(errorObject.e);
return null;
}
}
return xhr;
}
private serializeBody(body: any, contentType?: string) {
if (!body || typeof body === 'string') {
return body;
} else if (root.FormData && body instanceof root.FormData) {
return body;
}
if (contentType) {
const splitIndex = contentType.indexOf(';');
if (splitIndex !== -1) {
contentType = contentType.substring(0, splitIndex);
}
}
switch (contentType) {
case 'application/x-www-form-urlencoded':
return Object.keys(body).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(body[key])}`).join('&');
case 'application/json':
return JSON.stringify(body);
default:
return body;
}
}
private setHeaders(xhr: XMLHttpRequest, headers: Object) {
for (let key in headers) {
if (headers.hasOwnProperty(key)) {
xhr.setRequestHeader(key, headers[key]);
}
}
}
private setupEvents(xhr: XMLHttpRequest, request: AjaxRequest) {
const progressSubscriber = request.progressSubscriber;
function xhrTimeout(this: XMLHttpRequest, e: ProgressEvent) {
const {subscriber, progressSubscriber, request } = (<any>xhrTimeout);
if (progressSubscriber) {
progressSubscriber.error(e);
}
subscriber.error(new AjaxTimeoutError(this, request)); //TODO: Make betterer.
};
xhr.ontimeout = xhrTimeout;
(<any>xhrTimeout).request = request;
(<any>xhrTimeout).subscriber = this;
(<any>xhrTimeout).progressSubscriber = progressSubscriber;
if (xhr.upload && 'withCredentials' in xhr) {
if (progressSubscriber) {
let xhrProgress: (e: ProgressEvent) => void;
xhrProgress = function(e: ProgressEvent) {
const { progressSubscriber } = (<any>xhrProgress);
progressSubscriber.next(e);
};
if (root.XDomainRequest) {
xhr.onprogress = xhrProgress;
} else {
xhr.upload.onprogress = xhrProgress;
}
(<any>xhrProgress).progressSubscriber = progressSubscriber;
}
let xhrError: (e: ErrorEvent) => void;
xhrError = function(this: XMLHttpRequest, e: ErrorEvent) {
const { progressSubscriber, subscriber, request } = (<any>xhrError);
if (progressSubscriber) {
progressSubscriber.error(e);
}
subscriber.error(new AjaxError('ajax error', this, request));
};
xhr.onerror = xhrError;
(<any>xhrError).request = request;
(<any>xhrError).subscriber = this;
(<any>xhrError).progressSubscriber = progressSubscriber;
}
function xhrReadyStateChange(this: XMLHttpRequest, e: ProgressEvent) {
const { subscriber, progressSubscriber, request } = (<any>xhrReadyStateChange);
if (this.readyState === 4) {
// normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
let status: number = this.status === 1223 ? 204 : this.status;
let response: any = (this.responseType === 'text' ? (
this.response || this.responseText) : this.response);
// fix status code when it is 0 (0 status is undocumented).
// Occurs when accessing file resources or on Android 4.1 stock browser
// while retrieving files from application cache.
if (status === 0) {
status = response ? 200 : 0;
}
if (200 <= status && status < 300) {
if (progressSubscriber) {
progressSubscriber.complete();
}
subscriber.next(e);
subscriber.complete();
} else {
if (progressSubscriber) {
progressSubscriber.error(e);
}
subscriber.error(new AjaxError('ajax error ' + status, this, request));
}
}
};
xhr.onreadystatechange = xhrReadyStateChange;
(<any>xhrReadyStateChange).subscriber = this;
(<any>xhrReadyStateChange).progressSubscriber = progressSubscriber;
(<any>xhrReadyStateChange).request = request;
}
unsubscribe() {
const { done, xhr } = this;
if (!done && xhr && xhr.readyState !== 4 && typeof xhr.abort === 'function') {
xhr.abort();
}
super.unsubscribe();
}
}
/**
* A normalized AJAX response.
*
* @see {@link ajax}
*
* @class AjaxResponse
*/
export class AjaxResponse {
/** @type {number} The HTTP status code */
status: number;
/** @type {string|ArrayBuffer|Document|object|any} The response data */
response: any;
/** @type {string} The raw responseText */
responseText: string;
/** @type {string} The responseType (e.g. 'json', 'arraybuffer', or 'xml') */
responseType: string;
constructor(public originalEvent: Event, public xhr: XMLHttpRequest, public request: AjaxRequest) {
this.status = xhr.status;
this.responseType = xhr.responseType || request.responseType;
this.response = parseXhrResponse(this.responseType, xhr);
}
}
/**
* A normalized AJAX error.
*
* @see {@link ajax}
*
* @class AjaxError
*/
export class AjaxError extends Error {
/** @type {XMLHttpRequest} The XHR instance associated with the error */
xhr: XMLHttpRequest;
/** @type {AjaxRequest} The AjaxRequest associated with the error */
request: AjaxRequest;
/** @type {number} The HTTP status code */
status: number;
/** @type {string} The responseType (e.g. 'json', 'arraybuffer', or 'xml') */
responseType: string;
/** @type {string|ArrayBuffer|Document|object|any} The response data */
response: any;
constructor(message: string, xhr: XMLHttpRequest, request: AjaxRequest) {
super(message);
this.message = message;
this.xhr = xhr;
this.request = request;
this.status = xhr.status;
this.responseType = xhr.responseType || request.responseType;
this.response = parseXhrResponse(this.responseType, xhr);
}
}
function parseXhrResponse(responseType: string, xhr: XMLHttpRequest) {
switch (responseType) {
case 'json':
if ('response' in xhr) {
//IE does not support json as responseType, parse it internally
return xhr.responseType ? xhr.response : JSON.parse(xhr.response || xhr.responseText || 'null');
} else {
// HACK(benlesh): TypeScript shennanigans
// tslint:disable-next-line:no-any latest TS seems to think xhr is "never" here.
return JSON.parse((xhr as any).responseText || 'null');
}
case 'xml':
return xhr.responseXML;
case 'text':
default:
// HACK(benlesh): TypeScript shennanigans
// tslint:disable-next-line:no-any latest TS seems to think xhr is "never" here.
return ('response' in xhr) ? xhr.response : (xhr as any).responseText;
}
}
/**
* @see {@link ajax}
*
* @class AjaxTimeoutError
*/
export class AjaxTimeoutError extends AjaxError {
constructor(xhr: XMLHttpRequest, request: AjaxRequest) {
super('ajax timeout', xhr, request);
}
}
+73
View File
@@ -0,0 +1,73 @@
import { Subscriber } from '../../Subscriber';
import { AjaxResponse } from './AjaxObservable';
/**
* @see {@link ajax}
*
* @interface
* @name AjaxRequest
* @noimport true
*/
export class AjaxRequestDoc {
/**
* @type {string}
*/
url: string = '';
/**
* @type {number}
*/
body: any = 0;
/**
* @type {string}
*/
user: string = '';
/**
* @type {boolean}
*/
async: boolean = false;
/**
* @type {string}
*/
method: string = '';
/**
* @type {Object}
*/
headers: Object = null;
/**
* @type {number}
*/
timeout: number = 0;
/**
* @type {string}
*/
password: string = '';
/**
* @type {boolean}
*/
hasContent: boolean = false;
/**
* @type {boolean}
*/
crossDomain: boolean = false;
/**
* @return {XMLHttpRequest}
*/
createXHR(): XMLHttpRequest {
return null;
}
/**
* @type {Subscriber}
*/
progressSubscriber: Subscriber<any> = null;
/**
* @param {AjaxResponse} response
* @return {T}
*/
resultSelector<T>(response: AjaxResponse): T {
return null;
}
/**
* @type {string}
*/
responseType: string = '';
}
+280
View File
@@ -0,0 +1,280 @@
import { Subject, AnonymousSubject } from '../../Subject';
import { Subscriber } from '../../Subscriber';
import { Observable } from '../../Observable';
import { Subscription } from '../../Subscription';
import { Operator } from '../../Operator';
import { root } from '../../util/root';
import { ReplaySubject } from '../../ReplaySubject';
import { Observer, NextObserver } from '../../Observer';
import { tryCatch } from '../../util/tryCatch';
import { errorObject } from '../../util/errorObject';
import { assign } from '../../util/assign';
export interface WebSocketSubjectConfig {
url: string;
protocol?: string | Array<string>;
resultSelector?: <T>(e: MessageEvent) => T;
openObserver?: NextObserver<Event>;
closeObserver?: NextObserver<CloseEvent>;
closingObserver?: NextObserver<void>;
WebSocketCtor?: { new(url: string, protocol?: string|Array<string>): WebSocket };
binaryType?: 'blob' | 'arraybuffer';
}
/**
* We need this JSDoc comment for affecting ESDoc.
* @extends {Ignored}
* @hide true
*/
export class WebSocketSubject<T> extends AnonymousSubject<T> {
url: string;
protocol: string|Array<string>;
socket: WebSocket;
openObserver: NextObserver<Event>;
closeObserver: NextObserver<CloseEvent>;
closingObserver: NextObserver<void>;
WebSocketCtor: { new(url: string, protocol?: string|Array<string>): WebSocket };
binaryType?: 'blob' | 'arraybuffer';
private _output: Subject<T>;
resultSelector(e: MessageEvent) {
return JSON.parse(e.data);
}
/**
* Wrapper around the w3c-compatible WebSocket object provided by the browser.
*
* @example <caption>Wraps browser WebSocket</caption>
*
* let socket$ = Observable.webSocket('ws://localhost:8081');
*
* socket$.subscribe(
* (msg) => console.log('message received: ' + msg),
* (err) => console.log(err),
* () => console.log('complete')
* );
*
* socket$.next(JSON.stringify({ op: 'hello' }));
*
* @example <caption>Wraps WebSocket from nodejs-websocket (using node.js)</caption>
*
* import { w3cwebsocket } from 'websocket';
*
* let socket$ = Observable.webSocket({
* url: 'ws://localhost:8081',
* WebSocketCtor: w3cwebsocket
* });
*
* socket$.subscribe(
* (msg) => console.log('message received: ' + msg),
* (err) => console.log(err),
* () => console.log('complete')
* );
*
* socket$.next(JSON.stringify({ op: 'hello' }));
*
* @param {string | WebSocketSubjectConfig} urlConfigOrSource the source of the websocket as an url or a structure defining the websocket object
* @return {WebSocketSubject}
* @static true
* @name webSocket
* @owner Observable
*/
static create<T>(urlConfigOrSource: string | WebSocketSubjectConfig): WebSocketSubject<T> {
return new WebSocketSubject<T>(urlConfigOrSource);
}
constructor(urlConfigOrSource: string | WebSocketSubjectConfig | Observable<T>, destination?: Observer<T>) {
if (urlConfigOrSource instanceof Observable) {
super(destination, <Observable<T>> urlConfigOrSource);
} else {
super();
this.WebSocketCtor = root.WebSocket;
this._output = new Subject<T>();
if (typeof urlConfigOrSource === 'string') {
this.url = urlConfigOrSource;
} else {
// WARNING: config object could override important members here.
assign(this, urlConfigOrSource);
}
if (!this.WebSocketCtor) {
throw new Error('no WebSocket constructor can be found');
}
this.destination = new ReplaySubject();
}
}
lift<R>(operator: Operator<T, R>): WebSocketSubject<R> {
const sock = new WebSocketSubject<R>(this, <any> this.destination);
sock.operator = operator;
return sock;
}
private _resetState() {
this.socket = null;
if (!this.source) {
this.destination = new ReplaySubject();
}
this._output = new Subject<T>();
}
// TODO: factor this out to be a proper Operator/Subscriber implementation and eliminate closures
multiplex(subMsg: () => any, unsubMsg: () => any, messageFilter: (value: T) => boolean) {
const self = this;
return new Observable((observer: Observer<any>) => {
const result = tryCatch(subMsg)();
if (result === errorObject) {
observer.error(errorObject.e);
} else {
self.next(result);
}
let subscription = self.subscribe(x => {
const result = tryCatch(messageFilter)(x);
if (result === errorObject) {
observer.error(errorObject.e);
} else if (result) {
observer.next(x);
}
},
err => observer.error(err),
() => observer.complete());
return () => {
const result = tryCatch(unsubMsg)();
if (result === errorObject) {
observer.error(errorObject.e);
} else {
self.next(result);
}
subscription.unsubscribe();
};
});
}
private _connectSocket() {
const { WebSocketCtor } = this;
const observer = this._output;
let socket: WebSocket = null;
try {
socket = this.protocol ?
new WebSocketCtor(this.url, this.protocol) :
new WebSocketCtor(this.url);
this.socket = socket;
if (this.binaryType) {
this.socket.binaryType = this.binaryType;
}
} catch (e) {
observer.error(e);
return;
}
const subscription = new Subscription(() => {
this.socket = null;
if (socket && socket.readyState === 1) {
socket.close();
}
});
socket.onopen = (e: Event) => {
const openObserver = this.openObserver;
if (openObserver) {
openObserver.next(e);
}
const queue = this.destination;
this.destination = Subscriber.create(
(x) => socket.readyState === 1 && socket.send(x),
(e) => {
const closingObserver = this.closingObserver;
if (closingObserver) {
closingObserver.next(undefined);
}
if (e && e.code) {
socket.close(e.code, e.reason);
} else {
observer.error(new TypeError('WebSocketSubject.error must be called with an object with an error code, ' +
'and an optional reason: { code: number, reason: string }'));
}
this._resetState();
},
( ) => {
const closingObserver = this.closingObserver;
if (closingObserver) {
closingObserver.next(undefined);
}
socket.close();
this._resetState();
}
);
if (queue && queue instanceof ReplaySubject) {
subscription.add((<ReplaySubject<T>>queue).subscribe(this.destination));
}
};
socket.onerror = (e: Event) => {
this._resetState();
observer.error(e);
};
socket.onclose = (e: CloseEvent) => {
this._resetState();
const closeObserver = this.closeObserver;
if (closeObserver) {
closeObserver.next(e);
}
if (e.wasClean) {
observer.complete();
} else {
observer.error(e);
}
};
socket.onmessage = (e: MessageEvent) => {
const result = tryCatch(this.resultSelector)(e);
if (result === errorObject) {
observer.error(errorObject.e);
} else {
observer.next(result);
}
};
}
/** @deprecated internal use only */ _subscribe(subscriber: Subscriber<T>): Subscription {
const { source } = this;
if (source) {
return source.subscribe(subscriber);
}
if (!this.socket) {
this._connectSocket();
}
let subscription = new Subscription();
subscription.add(this._output.subscribe(subscriber));
subscription.add(() => {
const { socket } = this;
if (this._output.observers.length === 0) {
if (socket && socket.readyState === 1) {
socket.close();
}
this._resetState();
}
});
return subscription;
}
unsubscribe() {
const { source, socket } = this;
if (socket && socket.readyState === 1) {
socket.close();
this._resetState();
}
super.unsubscribe();
if (!source) {
this.destination = new ReplaySubject();
}
}
}
+3
View File
@@ -0,0 +1,3 @@
import { AjaxObservable, AjaxCreationMethod } from './AjaxObservable';
export const ajax: AjaxCreationMethod = AjaxObservable.create;
+3
View File
@@ -0,0 +1,3 @@
import { WebSocketSubject } from './WebSocketSubject';
export const webSocket = WebSocketSubject.create;
+3
View File
@@ -0,0 +1,3 @@
import { EmptyObservable } from './EmptyObservable';
export const empty = EmptyObservable.create;
+3
View File
@@ -0,0 +1,3 @@
import { ForkJoinObservable } from './ForkJoinObservable';
export const forkJoin = ForkJoinObservable.create;
+3
View File
@@ -0,0 +1,3 @@
import { FromObservable } from './FromObservable';
export const from = FromObservable.create;
+3
View File
@@ -0,0 +1,3 @@
import { FromEventObservable } from './FromEventObservable';
export const fromEvent = FromEventObservable.create;
+3
View File
@@ -0,0 +1,3 @@
import { FromEventPatternObservable } from './FromEventPatternObservable';
export const fromEventPattern = FromEventPatternObservable.create;
+3
View File
@@ -0,0 +1,3 @@
import { PromiseObservable } from './PromiseObservable';
export const fromPromise = PromiseObservable.create;
+3
View File
@@ -0,0 +1,3 @@
import { GenerateObservable } from './GenerateObservable';
export const generate = GenerateObservable.create;
+3
View File
@@ -0,0 +1,3 @@
import { IfObservable } from './IfObservable';
export const _if = IfObservable.create;
+3
View File
@@ -0,0 +1,3 @@
import { IntervalObservable } from './IntervalObservable';
export const interval = IntervalObservable.create;
+101
View File
@@ -0,0 +1,101 @@
import { Observable, ObservableInput } from '../Observable';
import { IScheduler } from '../Scheduler';
import { ArrayObservable } from './ArrayObservable';
import { isScheduler } from '../util/isScheduler';
import { mergeAll } from '../operators/mergeAll';
/* tslint:disable:max-line-length */
export function merge<T>(v1: ObservableInput<T>, scheduler?: IScheduler): Observable<T>;
export function merge<T>(v1: ObservableInput<T>, concurrent?: number, scheduler?: IScheduler): Observable<T>;
export function merge<T, T2>(v1: ObservableInput<T>, v2: ObservableInput<T2>, scheduler?: IScheduler): Observable<T | T2>;
export function merge<T, T2>(v1: ObservableInput<T>, v2: ObservableInput<T2>, concurrent?: number, scheduler?: IScheduler): Observable<T | T2>;
export function merge<T, T2, T3>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, scheduler?: IScheduler): Observable<T | T2 | T3>;
export function merge<T, T2, T3>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, concurrent?: number, scheduler?: IScheduler): Observable<T | T2 | T3>;
export function merge<T, T2, T3, T4>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, scheduler?: IScheduler): Observable<T | T2 | T3 | T4>;
export function merge<T, T2, T3, T4>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, concurrent?: number, scheduler?: IScheduler): Observable<T | T2 | T3 | T4>;
export function merge<T, T2, T3, T4, T5>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, v5: ObservableInput<T5>, scheduler?: IScheduler): Observable<T | T2 | T3 | T4 | T5>;
export function merge<T, T2, T3, T4, T5>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, v5: ObservableInput<T5>, concurrent?: number, scheduler?: IScheduler): Observable<T | T2 | T3 | T4 | T5>;
export function merge<T, T2, T3, T4, T5, T6>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, v5: ObservableInput<T5>, v6: ObservableInput<T6>, scheduler?: IScheduler): Observable<T | T2 | T3 | T4 | T5 | T6>;
export function merge<T, T2, T3, T4, T5, T6>(v1: ObservableInput<T>, v2: ObservableInput<T2>, v3: ObservableInput<T3>, v4: ObservableInput<T4>, v5: ObservableInput<T5>, v6: ObservableInput<T6>, concurrent?: number, scheduler?: IScheduler): Observable<T | T2 | T3 | T4 | T5 | T6>;
export function merge<T>(...observables: (ObservableInput<T> | IScheduler | number)[]): Observable<T>;
export function merge<T, R>(...observables: (ObservableInput<any> | IScheduler | number)[]): Observable<R>;
/* tslint:enable:max-line-length */
/**
* Creates an output Observable which concurrently emits all values from every
* given input Observable.
*
* <span class="informal">Flattens multiple Observables together by blending
* their values into one Observable.</span>
*
* <img src="./img/merge.png" width="100%">
*
* `merge` subscribes to each given input Observable (as arguments), and simply
* forwards (without doing any transformation) all the values from all the input
* Observables to the output Observable. The output Observable only completes
* once all input Observables have completed. Any error delivered by an input
* Observable will be immediately emitted on the output Observable.
*
* @example <caption>Merge together two Observables: 1s interval and clicks</caption>
* var clicks = Rx.Observable.fromEvent(document, 'click');
* var timer = Rx.Observable.interval(1000);
* var clicksOrTimer = Rx.Observable.merge(clicks, timer);
* clicksOrTimer.subscribe(x => console.log(x));
*
* // Results in the following:
* // timer will emit ascending values, one every second(1000ms) to console
* // clicks logs MouseEvents to console everytime the "document" is clicked
* // Since the two streams are merged you see these happening
* // as they occur.
*
* @example <caption>Merge together 3 Observables, but only 2 run concurrently</caption>
* var timer1 = Rx.Observable.interval(1000).take(10);
* var timer2 = Rx.Observable.interval(2000).take(6);
* var timer3 = Rx.Observable.interval(500).take(10);
* var concurrent = 2; // the argument
* var merged = Rx.Observable.merge(timer1, timer2, timer3, concurrent);
* merged.subscribe(x => console.log(x));
*
* // Results in the following:
* // - First timer1 and timer2 will run concurrently
* // - timer1 will emit a value every 1000ms for 10 iterations
* // - timer2 will emit a value every 2000ms for 6 iterations
* // - after timer1 hits it's max iteration, timer2 will
* // continue, and timer3 will start to run concurrently with timer2
* // - when timer2 hits it's max iteration it terminates, and
* // timer3 will continue to emit a value every 500ms until it is complete
*
* @see {@link mergeAll}
* @see {@link mergeMap}
* @see {@link mergeMapTo}
* @see {@link mergeScan}
*
* @param {...ObservableInput} observables Input Observables to merge together.
* @param {number} [concurrent=Number.POSITIVE_INFINITY] Maximum number of input
* Observables being subscribed to concurrently.
* @param {Scheduler} [scheduler=null] The IScheduler to use for managing
* concurrency of input Observables.
* @return {Observable} an Observable that emits items that are the result of
* every input Observable.
* @static true
* @name merge
* @owner Observable
*/
export function merge<T, R>(...observables: Array<ObservableInput<any> | IScheduler | number>): Observable<R> {
let concurrent = Number.POSITIVE_INFINITY;
let scheduler: IScheduler = null;
let last: any = observables[observables.length - 1];
if (isScheduler(last)) {
scheduler = <IScheduler>observables.pop();
if (observables.length > 1 && typeof observables[observables.length - 1] === 'number') {
concurrent = <number>observables.pop();
}
} else if (typeof last === 'number') {
concurrent = <number>observables.pop();
}
if (scheduler === null && observables.length === 1 && observables[0] instanceof Observable) {
return <Observable<R>>observables[0];
}
return mergeAll(concurrent)(new ArrayObservable(<any>observables, scheduler)) as Observable<R>;
}
+3
View File
@@ -0,0 +1,3 @@
import { NeverObservable } from './NeverObservable';
export const never = NeverObservable.create;
+3
View File
@@ -0,0 +1,3 @@
import { ArrayObservable } from './ArrayObservable';
export const of = ArrayObservable.of;
+3
View File
@@ -0,0 +1,3 @@
import { onErrorResumeNextStatic } from '../operators/onErrorResumeNext';
export const onErrorResumeNext = onErrorResumeNextStatic;
+3
View File
@@ -0,0 +1,3 @@
import { PairsObservable } from './PairsObservable';
export const pairs = PairsObservable.create;
+100
View File
@@ -0,0 +1,100 @@
import { Observable } from '../Observable';
import { isArray } from '../util/isArray';
import { ArrayObservable } from '../observable/ArrayObservable';
import { Operator } from '../Operator';
import { Subscriber } from '../Subscriber';
import { Subscription, TeardownLogic } from '../Subscription';
import { OuterSubscriber } from '../OuterSubscriber';
import { InnerSubscriber } from '../InnerSubscriber';
import { subscribeToResult } from '../util/subscribeToResult';
/**
* Returns an Observable that mirrors the first source Observable to emit an item.
* @param {...Observables} ...observables sources used to race for which Observable emits first.
* @return {Observable} an Observable that mirrors the output of the first Observable to emit an item.
* @static true
* @name race
* @owner Observable
*/
export function race<T>(observables: Array<Observable<T>>): Observable<T>;
export function race<T>(observables: Array<Observable<any>>): Observable<T>;
export function race<T>(...observables: Array<Observable<T> | Array<Observable<T>>>): Observable<T>;
export function race<T>(...observables: Array<Observable<any> | Array<Observable<any>>>): Observable<T> {
// if the only argument is an array, it was most likely called with
// `race([obs1, obs2, ...])`
if (observables.length === 1) {
if (isArray(observables[0])) {
observables = <Array<Observable<any>>>observables[0];
} else {
return <Observable<any>>observables[0];
}
}
return new ArrayObservable<T>(<any>observables).lift(new RaceOperator<T>());
}
export class RaceOperator<T> implements Operator<T, T> {
call(subscriber: Subscriber<T>, source: any): TeardownLogic {
return source.subscribe(new RaceSubscriber(subscriber));
}
}
/**
* We need this JSDoc comment for affecting ESDoc.
* @ignore
* @extends {Ignored}
*/
export class RaceSubscriber<T> extends OuterSubscriber<T, T> {
private hasFirst: boolean = false;
private observables: Observable<any>[] = [];
private subscriptions: Subscription[] = [];
constructor(destination: Subscriber<T>) {
super(destination);
}
protected _next(observable: any): void {
this.observables.push(observable);
}
protected _complete() {
const observables = this.observables;
const len = observables.length;
if (len === 0) {
this.destination.complete();
} else {
for (let i = 0; i < len && !this.hasFirst; i++) {
let observable = observables[i];
let subscription = subscribeToResult(this, observable, observable, i);
if (this.subscriptions) {
this.subscriptions.push(subscription);
}
this.add(subscription);
}
this.observables = null;
}
}
notifyNext(outerValue: T, innerValue: T,
outerIndex: number, innerIndex: number,
innerSub: InnerSubscriber<T, T>): void {
if (!this.hasFirst) {
this.hasFirst = true;
for (let i = 0; i < this.subscriptions.length; i++) {
if (i !== outerIndex) {
let subscription = this.subscriptions[i];
subscription.unsubscribe();
this.remove(subscription);
}
}
this.subscriptions = null;
}
this.destination.next(innerValue);
}
}

Some files were not shown because too many files have changed in this diff Show More