All files state.ts

50% Statements 18/36
0% Branches 0/6
41.67% Functions 5/12
51.61% Lines 16/31
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 104 105 106 107 108 109 110 111 1121x   1x 1x                                                       1x   1x         1x 84x             1x 23x                 1x                     1x                                       1x 1x 1x 24x     1x                                    
import * as Immutable from 'seamless-immutable'
 
import { BehaviorSubject } from 'rxjs/BehaviorSubject'
import { Observable } from 'rxjs/Observable'
import { StateSelector } from './state-selector'
import { Subscription } from 'rxjs/Subscription'
 
/**
 * Defines a stream for changing state in a statex application
 *
 * @example
 *
 * // replace state
 * State.next(state)
 *
 * // subscribe to state stream
 * State.subscribe((state: State) => {
 *   // do your action here
 * })
 *
 * // or listen to a portion of the state
 * State
 *   .select((state: State) => state.application.pageContainer)
 *   .subscribe((state: State) => {
 *     // do your action here
 *   })
 *
 * @export
 * @class StateStream
 * @extends {BehaviorSubject}
 */
export class State {
 
  private static state: State = new State()
 
  private currentState: any
  private subject: BehaviorSubject<any>
 
  static get current() {
    return State.state.currentState
  }
 
  /**
   * Publish next state
   * @param state
   */
  static next(state) {
    State.state.subject.next(state)
  }
 
  /**
   * Subscribe to the stream
   * @param onNext
   * @param onError
   * @param onComplete
   */
  static subscribe(onNext, onError, onComplete): Subscription {
    return State.state.subject.subscribe(onNext, onError, onComplete)
  }
 
  /**
   * Fires 'next' only when the value returned by this function changed from the previous value.
   *
   * @template T
   * @param {StateSelector<T>} selector
   * @returns {Observable<T>}
   */
  static select(selector: StateSelector): Observable<any> {
 
    return Observable.create(subscriber => {
      let previousState: any
      let subscription = this.subscribe(
        state => {
          let selection = select(state, selector)
          if (selection !== select(previousState, selector)) {
            previousState = state
            subscriber.next(selection)
          }
        },
        error => subscriber.error(error),
        () => subscriber.complete()
      )
 
      return subscription
    }).share()
  }
 
  constructor() {
    this.currentState = Immutable.from<any>({})
    this.subject = new BehaviorSubject(this.currentState)
    this.subject.subscribe(state => this.currentState = state)
  }
 
}
 
/**
 * Run selector function on the given state and return it's result. Return undefined if an error occurred
 *
 * @param {*} state
 * @param {StateSelector} selector
 * @returns The value return by the selector, undefined if an error occurred.
 */
function select(state: any, selector: StateSelector) {
  if (state == undefined) return
  if (selector == undefined) return state
  try {
    return selector(state)
  } catch (error) {
    return undefined
  }
}