Code coverage report for src/operator/withLatestFrom.ts

Statements: 98.15% (53 / 54)      Branches: 91.67% (11 / 12)      Functions: 100% (9 / 9)      Lines: 98% (49 / 50)      Ignored: none     

All files » src/operator/ » withLatestFrom.ts
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101      1 1 1 1                                       38 12 12 2   12 12     1 12 12     1 12   1   1   12   1 12 12 12 12 12   12 24     12 24 24       1 46 46 46 26 26 18         1       1 17 11 11 11 11 11 4 4     4     7       1  
import {Operator} from '../Operator';
import {Subscriber} from '../Subscriber';
import {Observable} from '../Observable';
import {tryCatch} from '../util/tryCatch';
import {errorObject} from '../util/errorObject';
import {OuterSubscriber} from '../OuterSubscriber';
import {subscribeToResult} from '../util/subscribeToResult';
 
/**
 * @param {Observable} observables the observables to get the latest values from.
 * @param {Function} [project] optional projection function for merging values together. Receives all values in order
 *  of observables passed. (e.g. `a.withLatestFrom(b, c, (a1, b1, c1) => a1 + b1 + c1)`). If this is not passed, arrays
 *  will be returned.
 * @description merges each value from an observable with the latest values from the other passed observables.
 * All observables must emit at least one value before the resulting observable will emit
 *
 * #### example
 * ```
 * A.withLatestFrom(B, C)
 *
 *  A:     ----a-----------------b---------------c-----------|
 *  B:     ---d----------------e--------------f---------|
 *  C:     --x----------------y-------------z-------------|
 * result: ---([a,d,x])---------([b,e,y])--------([c,f,z])---|
 * ```
 */
export function withLatestFrom<R>(...args: Array<Observable<any> | ((...values: Array<any>) => R)>): Observable<R> {
  let project;
  if (typeof args[args.length - 1] === 'function') {
    project = args.pop();
  }
  const observables = <Observable<any>[]>args;
  return this.lift(new WithLatestFromOperator(observables, project));
}
 
class WithLatestFromOperator<T, R> implements Operator<T, R> {
  constructor(private observables: Observable<any>[],
              private project?: (...values: any[]) => Observable<R>) {
  }
 
  call(subscriber: Subscriber<T>): Subscriber<T> {
    return new WithLatestFromSubscriber<T, R>(subscriber, this.observables, this.project);
  }
}
 
class WithLatestFromSubscriber<T, R> extends OuterSubscriber<T, R> {
  private values: any[];
  private toRespond: number[] = [];
 
  constructor(destination: Subscriber<T>,
              private observables: Observable<any>[],
              private project?: (...values: any[]) => Observable<R>) {
    super(destination);
    const len = observables.length;
    this.values = new Array(len);
 
    for (let i = 0; i < len; i++) {
      this.toRespond.push(i);
    }
 
    for (let i = 0; i < len; i++) {
      let observable = observables[i];
      this.add(subscribeToResult<T, R>(this, observable, <any>observable, i));
    }
  }
 
  notifyNext(observable, value, observableIndex, index) {
    this.values[observableIndex] = value;
    const toRespond = this.toRespond;
    if (toRespond.length > 0) {
      const found = toRespond.indexOf(observableIndex);
      if (found !== -1) {
        toRespond.splice(found, 1);
      }
    }
  }
 
  notifyComplete() {
    // noop
  }
 
  _next(value: T) {
    if (this.toRespond.length === 0) {
      const values = this.values;
      const destination = this.destination;
      const project = this.project;
      const args = [value, ...values];
      if (project) {
        let result = tryCatch(this.project).apply(this, args);
        Iif (result === errorObject) {
          destination.error(result.e);
        } else {
          destination.next(result);
        }
      } else {
        destination.next(args);
      }
    }
  }
}