Code coverage report for src/observable/forkJoin.ts

Statements: 100% (64 / 64)      Branches: 100% (20 / 20)      Functions: 100% (10 / 10)      Lines: 100% (59 / 59)      Ignored: none     

All files » src/observable/ » forkJoin.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 102 103 1041 1 1 1 1 1   1 19 19 19     65       20 1     19 19 8         19 4     19     1 19 19   19 19 41 41 1   41     1   1 41   1 41 41       41     1 79     1 37   37 7     37 37 37 37   37 22     15 11   11     15   1   1 32     1 19 19 41   19    
import {Observable} from '../Observable';
import {Subscriber} from '../Subscriber';
import {PromiseObservable} from './fromPromise';
import {EmptyObservable} from './empty';
import {isPromise} from '../util/isPromise';
import {isArray} from '../util/isArray';
 
export class ForkJoinObservable<T> extends Observable<T> {
  constructor(private sources: Array<Observable<any> | Promise<any>>,
              private resultSelector?: (...values: Array<any>) => any) {
    super();
  }
 
  static create(...sources: Array<Observable<any> |
                                  Array<Observable<any>> |
                                  Promise<any> |
                                  ((...values: Array<any>) => any)>): Observable<any> {
    if (sources === null || arguments.length === 0) {
      return new EmptyObservable();
    }
 
    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<Observable<any>>>sources[0];
    }
 
    return new ForkJoinObservable(<Array<Observable<any> | Promise<any>>>sources, resultSelector);
  }
 
  _subscribe(subscriber: Subscriber<any>) {
    const sources = this.sources;
    const len = sources.length;
 
    const context = { completed: 0, total: len, values: emptyArray(len), selector: this.resultSelector };
    for (let i = 0; i < len; i++) {
      let source = sources[i];
      if (isPromise(source)) {
        source = new PromiseObservable(<Promise<any>>source);
      }
      (<Observable<any>>source).subscribe(new AllSubscriber(subscriber, i, context));
    }
  }
}
 
class AllSubscriber<T> extends Subscriber<T> {
  private _value: any = null;
 
  constructor(destination: Subscriber<any>,
              private index: number,
              private context: { completed: number,
                                 total: number,
                                 values: any[],
                                 selector: (...values: Array<any>) => any }) {
    super(destination);
  }
 
  _next(value: any): void {
    this._value = value;
  }
 
  _complete(): void {
    const destination = this.destination;
 
    if (this._value == null) {
      destination.complete();
    }
 
    const context = this.context;
    context.completed++;
    context.values[this.index] = this._value;
    const values = context.values;
 
    if (context.completed !== values.length) {
      return;
    }
 
    if (values.every(hasValue)) {
      let value = context.selector ? context.selector.apply(this, values) :
                                     values;
      destination.next(value);
    }
 
    destination.complete();
  }
}
 
function hasValue(x: any): boolean {
  return x !== null;
}
 
function emptyArray(len: number): any[] {
  let arr = [];
  for (let i = 0; i < len; i++) {
    arr.push(null);
  }
  return arr;
}