// we can disable shadowed variables here since we are performing type augmentations // tslint:disable no-shadowed-variable import { Iterable } from 'ix'; import { Observable } from 'rxjs/Observable'; import { PartialObserver } from 'rxjs/Observer'; import { IScheduler } from 'rxjs/Scheduler'; import { Subscription, TeardownLogic } from 'rxjs/Subscription'; import { Command, Property } from './Interfaces'; import { property } from './Property'; import { isSubscription } from './Utils'; export function filterNullIterable( this: Iterable, callbackfn?: (value: TFiltered, index: number) => boolean, ): Iterable { return (this as Iterable).filter((x, i) => { if (x == null) { return false; } return callbackfn == null ? true : callbackfn(x, i); }); } export function addSubscription( this: Subscription, subscription: T, ): T { this.add(subscription); return subscription; } export function addSubscriptions( this: Subscription, ...subscriptions: T[] ): T[] { return subscriptions.map(x => this.addSubscription(x)); } export function unsubscribeStatic( subscription: T, unsubscribedValue?: T, ): T { if (isSubscription(subscription)) { subscription.unsubscribe(); return unsubscribedValue || (Subscription.EMPTY as any); } return subscription; } export function filterNullObservable( this: Observable, callbackfn?: (value: T, index: number) => boolean, ): Observable { return (this as Observable).filter((x, i) => { if (x == null) { return false; } return callbackfn == null ? true : callbackfn(x, i); }); } export function toProperty( this: Observable, initialValue?: T, compare?: boolean | ((x: T, y: T) => boolean), keySelector?: (x: T) => any, ): Property { return property(initialValue, compare, keySelector, this); } export function observeCommand( this: Observable, command: ((x: T) => Command) | Command, ): Observable { // see the ReactiveUI project for the inspiration behind this function: // https://github.com/reactiveui/ReactiveUI/blob/master/src/ReactiveUI/ReactiveCommand.cs#L1078 return this.map(x => ({ parameter: x, command: command instanceof Function ? command(x) : command, })) .debounce(x => { return x.command.canExecuteObservable .startWith(x.command.canExecute) .filter(y => y) .map(() => 0); }) .map(x => { return x.command.observeExecution(x.parameter); }) .switch(); } export function invokeCommand( this: Observable, command: ((parameter: T) => Command) | Command, observer: PartialObserver, ): Subscription; export function invokeCommand( this: Observable, command: ((parameter: T) => Command) | Command, next?: (value: T) => void, error?: (error: any) => void, complete?: () => void, ): Subscription; export function invokeCommand( this: Observable, command: ((x: T) => Command) | Command, observerOrNext?: PartialObserver | ((value: TRet) => void), error?: (error: any) => void, complete?: () => void, ): Subscription { const obs = this.observeCommand(command); return obs.subscribe.apply(obs, [observerOrNext, error, complete]); } declare module 'ix/iterable/iterablex' { interface IterableX { filterNull: typeof filterNullIterable; } } declare module 'rxjs/Subscription' { interface Subscription { addSubscription: typeof addSubscription; addSubscriptions: typeof addSubscriptions; } namespace Subscription { let unsubscribe: typeof unsubscribeStatic; } } declare module 'rxjs/Observable' { interface Observable { filterNull: typeof filterNullObservable; toProperty: typeof toProperty; observeCommand: typeof observeCommand; invokeCommand: typeof invokeCommand; } } // there is no new implementation for startWith, only additional typings declare module 'rxjs/operator/startWith' { function startWith( this: Observable, value: TOther, scheduler?: IScheduler, ): Observable; function startWith( this: Observable, ...array: Array ): Observable; } Iterable.prototype.filterNull = filterNullIterable; Subscription.prototype.addSubscription = addSubscription; Subscription.prototype.addSubscriptions = addSubscriptions; Subscription.unsubscribe = unsubscribeStatic; Observable.prototype.filterNull = filterNullObservable; Observable.prototype.toProperty = toProperty; Observable.prototype.observeCommand = observeCommand; Observable.prototype.invokeCommand = invokeCommand;