Skip to content

Commit

Permalink
feat(compat): add next rxjs version's exports for forward compatibility
Browse files Browse the repository at this point in the history
* Also adds throwIfEmpty operator
  • Loading branch information
jasonaden committed Mar 20, 2018
1 parent e2d3bdb commit de37095
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 5 deletions.
6 changes: 4 additions & 2 deletions .make-packages.js
Expand Up @@ -39,8 +39,10 @@ fs.removeSync(PKG_ROOT);

let rootPackageJson = Object.assign({}, pkg, {
name: 'rxjs',
main: './Rx.js',
typings: './Rx.d.ts'
main: './index.js',
module: './_esm5/index.js',
es2015: './_esm2015/index.js',
typings: './index.d.ts'
});

// Get a list of the file names. Sort in reverse order so re-export files
Expand Down
122 changes: 122 additions & 0 deletions spec/operators/throwIfEmpty-spec.ts
@@ -0,0 +1,122 @@
import { expect } from 'chai';
import { cold, expectObservable, expectSubscriptions } from '../helpers/marble-testing';
import * as Rx from '../../dist/package/Rx';

/** @test {timeout} */
describe('throwIfEmpty', () => {
describe('with errorFactory', () => {
it('should throw if empty', () => {
const error = new Error('So empty inside');
let thrown: any;

Rx.Observable.empty().throwIfEmpty(() => error)
.subscribe({
error(err) {
thrown = err;
}
});

expect(thrown).to.equal(error);
});

it('should NOT throw if NOT empty', () => {
const error = new Error('So empty inside');
let thrown: any;

Rx.Observable.of('test').throwIfEmpty(() => error)
.subscribe({
error(err) {
thrown = err;
}
});

// tslint:disable-next-line:no-unused-expression
expect(thrown).to.be.undefined;
});

it('should pass values through', () => {
const source = cold('----a---b---c---|');
const sub1 = '^ !';
const expected = '----a---b---c---|';
expectObservable(
source.throwIfEmpty(() => new Error('test'))
).toBe(expected);
expectSubscriptions(source.subscriptions).toBe([sub1]);
});

it('should never when never', () => {
const source = cold('-');
const sub1 = '^';
const expected = '-';
expectObservable(
source.throwIfEmpty(() => new Error('test'))
).toBe(expected);
expectSubscriptions(source.subscriptions).toBe([sub1]);
});

it('should error when empty', () => {
const source = cold('----|');
const sub1 = '^ !';
const expected = '----#';
expectObservable(
source.throwIfEmpty(() => new Error('test'))
).toBe(expected, undefined, new Error('test'));
expectSubscriptions(source.subscriptions).toBe([sub1]);
});
});

describe('without errorFactory', () => {
it('should throw EmptyError if empty', () => {
let thrown: any;

Rx.Observable.empty().throwIfEmpty()
.subscribe({
error(err) {
thrown = err;
}
});

expect(thrown).to.be.instanceof(Rx.EmptyError);
});

it('should NOT throw if NOT empty', () => {
let thrown: any;

Rx.Observable.of('test').throwIfEmpty()
.subscribe({
error(err) {
thrown = err;
}
});

// tslint:disable-next-line:no-unused-expression
expect(thrown).to.be.undefined;
});

it('should pass values through', () => {
const source = cold('----a---b---c---|');
const sub1 = '^ !';
const expected = '----a---b---c---|';
expectObservable(source.throwIfEmpty()).toBe(expected);
expectSubscriptions(source.subscriptions).toBe([sub1]);
});

it('should never when never', () => {
const source = cold('-');
const sub1 = '^';
const expected = '-';
expectObservable(source.throwIfEmpty()).toBe(expected);
expectSubscriptions(source.subscriptions).toBe([sub1]);
});

it('should error when empty', () => {
const source = cold('----|');
const sub1 = '^ !';
const expected = '----#';
expectObservable(
source.throwIfEmpty()
).toBe(expected, undefined, new Rx.EmptyError());
expectSubscriptions(source.subscriptions).toBe([sub1]);
});
});
});
9 changes: 6 additions & 3 deletions src/Notification.ts
@@ -1,5 +1,8 @@
import { PartialObserver } from './Observer';
import { Observable } from './Observable';
import { of } from './observable/of';
import { empty } from './observable/empty';
import { _throw } from './observable/throw';

/**
* Represents a push-based event or value that an {@link Observable} can emit.
Expand Down Expand Up @@ -84,11 +87,11 @@ export class Notification<T> {
const kind = this.kind;
switch (kind) {
case 'N':
return Observable.of(this.value);
return of(this.value);
case 'E':
return Observable.throw(this.error);
return _throw(this.error);
case 'C':
return Observable.empty<T>();
return empty<T>();
}
throw new Error('unexpected notification kind value');
}
Expand Down
7 changes: 7 additions & 0 deletions src/Rx.ts
Expand Up @@ -128,6 +128,7 @@ import './add/operator/takeUntil';
import './add/operator/takeWhile';
import './add/operator/throttle';
import './add/operator/throttleTime';
import './add/operator/throwIfEmpty';
import './add/operator/timeInterval';
import './add/operator/timeout';
import './add/operator/timeoutWith';
Expand Down Expand Up @@ -177,9 +178,15 @@ import { rxSubscriber } from './symbol/rxSubscriber';
import { iterator } from './symbol/iterator';
import { observable } from './symbol/observable';

import * as _ajax from './ajax';
import * as _operators from './operators';
import * as _testing from './testing';
import * as _websocket from './websocket';

export const ajax = _ajax;
export const operators = _operators;
export const testing = _testing;
export const websocket = _websocket;

/* tslint:enable:no-unused-variable */

Expand Down
11 changes: 11 additions & 0 deletions src/add/operator/throwIfEmpty.ts
@@ -0,0 +1,11 @@

import { Observable } from '../../Observable';
import { throwIfEmpty } from '../../operator/throwIfEmpty';

Observable.prototype.throwIfEmpty = throwIfEmpty;

declare module '../../Observable' {
interface Observable<T> {
throwIfEmpty: typeof throwIfEmpty;
}
}
2 changes: 2 additions & 0 deletions src/ajax.ts
@@ -0,0 +1,2 @@
export { ajax } from './observable/dom/ajax';
export { AjaxRequest, AjaxResponse, AjaxError, AjaxTimeoutError } from './observable/dom/AjaxObservable';
7 changes: 7 additions & 0 deletions src/operator/throwIfEmpty.ts
@@ -0,0 +1,7 @@
import { Observable } from '../Observable';
import { throwIfEmpty as higherOrder, defaultErrorFactory } from '../operators/throwIfEmpty';

export function throwIfEmpty<T>(this: Observable<T>,
errorFactory: (() => any) = defaultErrorFactory): Observable<T> {
return higherOrder(errorFactory)(this) as Observable<T>;
}
1 change: 1 addition & 0 deletions src/operators.ts
Expand Up @@ -93,6 +93,7 @@ export { takeWhile } from './operators/takeWhile';
export { tap } from './operators/tap';
export { throttle } from './operators/throttle';
export { throttleTime } from './operators/throttleTime';
export { throwIfEmpty } from './operators/throwIfEmpty';
export { timeInterval } from './operators/timeInterval';
export { timeout } from './operators/timeout';
export { timeoutWith } from './operators/timeoutWith';
Expand Down
43 changes: 43 additions & 0 deletions src/operators/throwIfEmpty.ts
@@ -0,0 +1,43 @@
import { tap } from './tap';
import { EmptyError } from '../util/EmptyError';
/* tslint:disable:no-unused-variable */
import { Observable } from '../Observable';
/* tslint:enable:no-unused-variable */

/**
* If the source observable completes without emitting a value, it will emit
* an error. The error will be created at that time by the optional
* `errorFactory` argument, otherwise, the error will be {@link ErrorEmpty}.
*
* @example
*
* const click$ = fromEvent(button, 'click');
*
* clicks$.pipe(
* takeUntil(timer(1000)),
* throwIfEmpty(
* () => new Error('the button was not clicked within 1 second')
* ),
* )
* .subscribe({
* next() { console.log('The button was clicked'); },
* error(err) { console.error(err); },
* });
* @param {Function} [errorFactory] A factory function called to produce the
* error to be thrown when the source observable completes without emitting a
* value.
*/
export const throwIfEmpty =
<T>(errorFactory: (() => any) = defaultErrorFactory) => tap<T>({
hasValue: false,
next(this: any) { this.hasValue = true; },
complete(this: any) {
if (!this.hasValue) {
throw errorFactory();
}
}
} as any);

export function defaultErrorFactory() {
return new EmptyError();
}
1 change: 1 addition & 0 deletions src/testing.ts
@@ -0,0 +1 @@
export { TestScheduler } from './testing/TestScheduler';
1 change: 1 addition & 0 deletions src/websocket.ts
@@ -0,0 +1 @@
export { webSocket as websocket } from './observable/dom/webSocket';

0 comments on commit de37095

Please sign in to comment.