Comparing version 1.2.0 to 1.2.1
export declare function isFunction(fn: any): fn is Function; | ||
export declare function filterNonFunctions(...fns: any[]): Function[]; | ||
export declare function fail(message?: string, ...args: any[]): void; |
@@ -11,1 +11,11 @@ export function isFunction(fn) { | ||
} | ||
/* istanbul ignore next */ | ||
export function fail(message) { | ||
if (message === void 0) { message = ""; } | ||
var args = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
args[_i - 1] = arguments[_i]; | ||
} | ||
var errorMsg = "Test failed\n" + message + " " + args.reduce(function (acc, curr) { return acc + " " + curr; }, ""); | ||
throw new Error(errorMsg); | ||
} |
@@ -1,2 +0,2 @@ | ||
export * from './fleuve/fleuve'; | ||
export * from './operators/index'; | ||
export * from './observable'; | ||
export * from './operators'; |
@@ -1,2 +0,2 @@ | ||
export * from './fleuve/fleuve'; | ||
export * from './operators/index'; | ||
export * from './observable'; | ||
export * from './operators'; |
@@ -5,3 +5,3 @@ export declare class EventSubscription { | ||
private listener; | ||
constructor(elem: Element, eventType: string, listener: EventListener); | ||
constructor(elem: Element, eventType: keyof HTMLElementEventMap, listener: EventListener); | ||
unsubscribe: () => void; | ||
@@ -8,0 +8,0 @@ } |
@@ -5,13 +5,17 @@ export declare type OperatorFunction<T, U = never> = (source: T) => U; | ||
private _flag?; | ||
constructor(_value: T, _flag?: OperationResultFlag | undefined); | ||
private _error?; | ||
constructor(_value: T, _flag?: OperationResultFlag | undefined, _error?: Error | undefined); | ||
get value(): T; | ||
get flag(): OperationResultFlag | undefined; | ||
get error(): Error | undefined; | ||
isUnwrapSwitch(): boolean; | ||
isMustStop(): boolean; | ||
isFilterNotMatched(): boolean; | ||
isOperationError(): boolean; | ||
} | ||
export declare enum OperationResultFlag { | ||
UnwrapSwitch = 0, | ||
MustStop = 1, | ||
FilterNotMatched = 2 | ||
UnwrapSwitch = "UnwrapSwitch", | ||
MustStop = "MustStop", | ||
FilterNotMatched = "FilterNotMatched", | ||
OperationError = "OperationError" | ||
} |
var OperationResult = /** @class */ (function () { | ||
function OperationResult(_value, _flag) { | ||
function OperationResult(_value, _flag, _error) { | ||
this._value = _value; | ||
this._flag = _flag; | ||
this._error = _error; | ||
} | ||
@@ -20,2 +21,9 @@ Object.defineProperty(OperationResult.prototype, "value", { | ||
}); | ||
Object.defineProperty(OperationResult.prototype, "error", { | ||
get: function () { | ||
return this._error; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
OperationResult.prototype.isUnwrapSwitch = function () { | ||
@@ -30,2 +38,5 @@ return this._flag === OperationResultFlag.UnwrapSwitch; | ||
}; | ||
OperationResult.prototype.isOperationError = function () { | ||
return this._flag === OperationResultFlag.OperationError; | ||
}; | ||
return OperationResult; | ||
@@ -36,5 +47,6 @@ }()); | ||
(function (OperationResultFlag) { | ||
OperationResultFlag[OperationResultFlag["UnwrapSwitch"] = 0] = "UnwrapSwitch"; | ||
OperationResultFlag[OperationResultFlag["MustStop"] = 1] = "MustStop"; | ||
OperationResultFlag[OperationResultFlag["FilterNotMatched"] = 2] = "FilterNotMatched"; | ||
OperationResultFlag["UnwrapSwitch"] = "UnwrapSwitch"; | ||
OperationResultFlag["MustStop"] = "MustStop"; | ||
OperationResultFlag["FilterNotMatched"] = "FilterNotMatched"; | ||
OperationResultFlag["OperationError"] = "OperationError"; | ||
})(OperationResultFlag || (OperationResultFlag = {})); |
export declare class Subscription { | ||
private _unsubscribeCallback; | ||
constructor(_unsubscribeCallback: UnsubscribeCallback); | ||
private _unsubscribeCallback?; | ||
constructor(_unsubscribeCallback?: UnsubscribeCallback | undefined); | ||
unsubscribe(): void; | ||
} | ||
export declare const EMPTY_SUBSCRIPTION: Subscription; | ||
interface UnsubscribeCallback { | ||
@@ -10,8 +11,8 @@ (): void; | ||
export interface Subscriber<T = any> { | ||
next: OnNext<T>; | ||
next?: OnNext<T>; | ||
error?: OnError; | ||
complete?: OnComplete<T>; | ||
complete?: OnComplete; | ||
} | ||
export declare function isInstanceOfSubscriber(obj: any): obj is Subscriber; | ||
export declare function subscriberOf<T>(next: OnNext<T>, error?: OnError, complete?: OnComplete<T>): Subscriber<T>; | ||
export declare function subscriberOf<T>(next?: OnNext<T>, error?: OnError, complete?: OnComplete): Subscriber<T>; | ||
export interface OnNext<T> { | ||
@@ -23,5 +24,5 @@ (t: T): void; | ||
} | ||
export interface OnComplete<T> { | ||
(result: T | Error | undefined): void; | ||
export interface OnComplete { | ||
(): void; | ||
} | ||
export {}; |
@@ -7,3 +7,3 @@ import { isFunction } from "../helpers/function.helper"; | ||
Subscription.prototype.unsubscribe = function () { | ||
this._unsubscribeCallback(); | ||
this._unsubscribeCallback && this._unsubscribeCallback(); | ||
}; | ||
@@ -13,11 +13,20 @@ return Subscription; | ||
export { Subscription }; | ||
export var EMPTY_SUBSCRIPTION = new Subscription(); | ||
export function isInstanceOfSubscriber(obj) { | ||
return isFunction(obj.next) && (obj.error === undefined || isFunction(obj.error)) && (obj.complete == undefined || isFunction(obj.complete)); | ||
function hasAtLeastOneOfTheseFieldsAsAFunction(obj) { | ||
var fields = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
fields[_i - 1] = arguments[_i]; | ||
} | ||
return fields.some(function (field) { return obj[field] !== undefined && obj[field] !== null && isFunction(obj[field]); }); | ||
} | ||
return !isFunction(obj) && hasAtLeastOneOfTheseFieldsAsAFunction(obj, 'next', 'error', 'complete'); | ||
} | ||
export function subscriberOf(next, error, complete) { | ||
if (!isInstanceOfSubscriber({ next: next, error: error, complete: complete })) { | ||
throw new Error("Please provide functions for onNext, onError and onComplete"); | ||
var subscriber = { next: next, error: error, complete: complete }; | ||
if (!isInstanceOfSubscriber(subscriber)) { | ||
throw new Error("Please provide functions for next, error and complete"); | ||
} | ||
return { next: next, error: error, complete: complete }; | ||
return subscriber; | ||
} | ||
; |
export * from './predicates'; | ||
export * from './transform'; | ||
export * from './side-effects'; | ||
export * from './static'; |
export * from './predicates'; | ||
export * from './transform'; | ||
export * from './side-effects'; | ||
export * from './static'; |
@@ -1,3 +0,2 @@ | ||
import { Fleuve } from "../../fleuve/fleuve"; | ||
import { OperatorFunction, OperationResult } from "../../models/operator"; | ||
export declare const ifElse: <T = any, U = any>(predicate: OperatorFunction<T, boolean>, ifs: OperatorFunction<T, OperationResult<U>>[], elses?: OperatorFunction<T, OperationResult<U>>[] | undefined) => OperatorFunction<T, OperationResult<Fleuve<U>>>; | ||
export declare const ifElse: <T = any, U = any>(predicate: OperatorFunction<T, boolean>, ifs: OperatorFunction<T, OperationResult<U>>[], elses?: OperatorFunction<T, OperationResult<U>>[] | undefined) => OperatorFunction<T, OperationResult<T | U>>; |
@@ -1,11 +0,12 @@ | ||
import { OperationResult, OperationResultFlag, } from "../../models/operator"; | ||
import { of } from "../static/creation/of"; | ||
import { filter } from "./filter"; | ||
export var ifElse = function (predicate, ifs, elses) { | ||
return function (source) { | ||
var _a, _b; | ||
var operationResult = filter(predicate)(source); | ||
return new OperationResult(!operationResult.isFilterNotMatched() | ||
? (_a = of(source)).pipe.apply(_a, ifs) : (_b = of(source)).pipe.apply(_b, (elses !== null && elses !== void 0 ? elses : [])), OperationResultFlag.UnwrapSwitch); | ||
var operators = !operationResult.isFilterNotMatched() ? ifs : (elses !== null && elses !== void 0 ? elses : []); | ||
var start = operators.shift(); | ||
if (start) { | ||
return operators.reduce(function (acc, curr) { return curr(acc.value); }, start(source)); | ||
} | ||
return operationResult; | ||
}; | ||
}; |
@@ -0,3 +1,4 @@ | ||
export * from './as-long-as'; | ||
export * from './filter'; | ||
export * from './as-long-as'; | ||
export * from './if-else'; | ||
export * from './until'; |
@@ -0,3 +1,4 @@ | ||
export * from './as-long-as'; | ||
export * from './filter'; | ||
export * from './as-long-as'; | ||
export * from './if-else'; | ||
export * from './until'; |
@@ -1,2 +0,2 @@ | ||
import { Fleuve } from "../../../fleuve/fleuve"; | ||
export declare const of: <T>(value: T) => Fleuve<T>; | ||
import { Observable } from "../../../observable"; | ||
export declare const of: <T = never>(...values: T[]) => Observable<T>; |
@@ -1,7 +0,13 @@ | ||
import { Fleuve } from "../../../fleuve/fleuve"; | ||
export var of = function (value) { | ||
var fleuve$ = new Fleuve(value); | ||
fleuve$.close(); | ||
fleuve$._isFinite = true; | ||
return fleuve$; | ||
var __spreadArray = (this && this.__spreadArray) || function (to, from) { | ||
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++) | ||
to[j] = from[i]; | ||
return to; | ||
}; | ||
import { Observable } from "../../../observable"; | ||
export var of = function () { | ||
var values = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
values[_i] = arguments[_i]; | ||
} | ||
return new (Observable.bind.apply(Observable, __spreadArray([void 0], values)))(); | ||
}; |
@@ -1,3 +0,3 @@ | ||
import { Fleuve } from "../../../fleuve/fleuve"; | ||
import { OperationResult, OperatorFunction } from "../../../models/operator"; | ||
export declare function preProcess<T = never>(...operations: OperatorFunction<any, OperationResult<T>>[]): Fleuve<T>; | ||
import { MutableObservable } from "../../../observable"; | ||
export declare function preProcess<T = never>(...operations: OperatorFunction<any, OperationResult<T>>[]): MutableObservable<T>; |
@@ -1,2 +0,2 @@ | ||
import { Fleuve } from "../../../fleuve/fleuve"; | ||
import { MutableObservable } from "../../../observable"; | ||
export function preProcess() { | ||
@@ -8,5 +8,5 @@ var _a; | ||
} | ||
var fleuve$ = new Fleuve(); | ||
(_a = fleuve$._preProcessOperations).push.apply(_a, operations); | ||
return fleuve$; | ||
var obs$ = new MutableObservable(); | ||
(_a = obs$._preProcessOperations).push.apply(_a, operations); | ||
return obs$; | ||
} |
@@ -1,3 +0,3 @@ | ||
import { Fleuve } from "../../fleuve/fleuve"; | ||
import { OperationResult, OperatorFunction } from "../../models/operator"; | ||
export declare function switchMap<T = any, U = T>(f: OperatorFunction<T, Fleuve<U>>): OperatorFunction<T, OperationResult<Fleuve<U>>>; | ||
import { Observable } from "../../observable/observable"; | ||
export declare function switchMap<T = any, U = T>(f: OperatorFunction<T, Observable<U>>): OperatorFunction<T, OperationResult<Observable<U>>>; |
@@ -8,5 +8,5 @@ module.exports = { | ||
"global": { | ||
"branches": 95, | ||
"functions": 95, | ||
"lines": 95, | ||
"branches": 90, | ||
"functions": 90, | ||
"lines": 90, | ||
"statements": 0 | ||
@@ -13,0 +13,0 @@ } |
{ | ||
"name": "fleuvejs", | ||
"version": "1.2.0", | ||
"version": "1.2.1", | ||
"description": "A simple JavaScript Library for Observables", | ||
@@ -12,3 +12,3 @@ "main": "build/index.js", | ||
"type": "git", | ||
"url": "git+https://github.com/nugetchar/FleuveJS.git" | ||
"url": "git+https://github.com/nugetchar/ObservableJS.git" | ||
}, | ||
@@ -15,0 +15,0 @@ "keywords": [ |
210
README.md
@@ -1,4 +0,4 @@ | ||
# FleuveJS | ||
# ObservableJS | ||
![logo](https://github.com/nugetchar/FleuveJS/blob/main/logo.png) | ||
![logo](https://github.com/nugetchar/ObservableJS/blob/main/logo.png) | ||
@@ -8,14 +8,14 @@ A simple Observable Utility library. | ||
## Why? | ||
Fleuve is called that way because of the philosophy behind: every Fleuve is a data stream, potentially infinite. | ||
You can add your own data to the Fleuve, and everyone on the Fleuve will be notified. | ||
Observable is called that way because of the philosophy behind: every Observable is a data stream, potentially infinite. | ||
You can add your own data to the Observable, and everyone on the Observable will be notified. | ||
You can also add some pipeline to the Fleuve, so what you receive has been processed in a convenient way before. | ||
You can also add some pipeline to the Observable, so what you receive has been processed in a convenient way before. | ||
You can bind a Fleuve behavior to the user's behavior. | ||
You can bind an Observable behavior to the user's behavior. | ||
A Fleuve can be forked into multiple other Fleuves: each Fleuve child will dispatch some data everytime their parent dispatch some data. You can also close your stream of data, and everyone will know the Fleuve is complete. | ||
A Observable can be forked into multiple other Observables: each Observable child will dispatch some data everytime their parent dispatch some data. You can also close your stream of data, and everyone will know the Observable is complete. | ||
In short: | ||
- potentially infinite source of data; | ||
- cascading Fleuves by forking a data stream; | ||
- cascading Observables by forking a data stream; | ||
- data pre-processing; | ||
@@ -27,3 +27,3 @@ - aims to allow practically anything as a source of data: a function execution, a user's action, a scalar value, a websocket... | ||
## Installation | ||
`npm i fleuvejs` | ||
`npm i observablejs` | ||
@@ -33,35 +33,28 @@ Or, if you'd prefer to work on a vanilla project: | ||
```js | ||
import { Fleuve } from 'https://unpkg.com/browse/fleuvejs@latest/bundle/fleuve.bundle.js'; | ||
import { Observable } from 'https://unpkg.com/observablejs@latest/bundle/observable.bundle.js'; | ||
``` | ||
## How To Use | ||
## Observables and MutableObservables | ||
### Instantiate a Fleuve | ||
`Observables` are objects containing an inner sequence. Their sequence is finite, and they are immutable. | ||
`MutableObservables` are objects containing an inner sequence too, except this one can be mutated over time. It is infinite, and can be completed with the `.close()` method. | ||
`ObservableFork` are objects created from either `Observable`, `MutableObservable` or `ObservableFork`: | ||
- they can be closed; | ||
- they can be potentially infinite; | ||
- they **cannot** be mutated; | ||
- they can come with pre-processing operations: when the source emits a new value, the pre-processing operations will be executed on it before being passed to the fork's subscribers. | ||
*Warning: soon to be deprecated in favor of static operators `of` and `from`* | ||
```ts | ||
const johnDoe$ = new Fleuve({firstname: 'john', lastname: 'doe'}); | ||
const counter$ = new Fleuve(0); | ||
``` | ||
## How To Use Observables | ||
### Provide new values with `next` and `compile` | ||
## Instantiate an Observable | ||
```ts | ||
const fleuve$ = new Fleuve(0); | ||
fleuve$.next(12, 13, 14, 15, 16); // fleuve$ inner value will go from 12 to 16 | ||
fleuve$.compile(map((x) => x + 1), map((x) => x * 2)); // fleuve$ inner value will go from 16 to 17, then from 17 to 34 | ||
const temperatures$ = of(10, 20, 13, 24); | ||
``` | ||
### Close a fleuve with `close` | ||
### Pipe the Observable | ||
You can create a new Observable with the `pipe` method. | ||
```ts | ||
const fleuve$ = new Fleuve(0); | ||
fleuve$.close(); | ||
``` | ||
### Pipe the Fleuve | ||
You can create a new Fleuve with the `pipe` method. | ||
```ts | ||
const fleuve$ = new Fleuve(18729); | ||
const sum$ = fleuve$.pipe( | ||
const obs$ = of(18729); | ||
const sum$ = obs$.pipe( | ||
map((x) => (x + '').split('')), | ||
@@ -72,19 +65,24 @@ map((numbers) => numbers.reduce((acc, curr) => acc + curr, 0)) | ||
### Subscribe | ||
### Subscribe to the Observable | ||
```ts | ||
const fleuve$ = new Fleuve(12); | ||
fleuve$.subscribe((value) => console.log(value), (err) => console.error(err), () => console.log('fleuve complete')); | ||
const obs$ = of(12); | ||
obs$.subscribe({ | ||
next: (value) => console.log(value), | ||
error: (err) => console.error(err), | ||
compleyte: () => console.log('observable complete') | ||
}); | ||
const empty$ = new Fleuve(); | ||
const empty$ = of(); | ||
empty$.subscribe((value) => console.log(value)); // will never execute; | ||
// This one will throw an error | ||
fleuve$.subscribe(42); | ||
obs$.subscribe(42); | ||
// You can as well create a Subscriber object | ||
fleuve$.subscribe(subscriberOf((x) => console.log(x))); | ||
obs$.subscribe(subscriberOf((x) => console.log(x))); | ||
``` | ||
### Add an event listener | ||
You can bind users interactions to a Fleuve. | ||
You can bind users interactions to an Observable. | ||
@@ -96,36 +94,50 @@ ```html | ||
```js | ||
const fleuve$ = new Fleuve(); | ||
const eventSubscription = fleuve$.addEventListener('#clickMe', 'click', (x, event) => console.log(x, event)) | ||
const obs$ = onEvent(document.getElementById("clickMe"), "click"); | ||
obs$.subscribe((event) => console.log('event triggered', event)); | ||
``` | ||
### Remove an event listener | ||
```js | ||
eventSubscription.unsubscribe(); | ||
## How To Use MutableObservables | ||
`MutableObservable` simply extends `Observable`. All of the previous sections also apply to `MutableObservable`. | ||
### Provide new values with `next` and `compile` | ||
```ts | ||
const obs$ = mutable(0); | ||
obs$.next(12, 13, 14, 15, 16); // obs$ inner sequence will now be [ 12, 13, 14, 15, 16 ] | ||
obs$.compile(map((x) => x + 1), map((x) => x * 2)); // obs$ inner sequence will now be [ 26, 28, 30, 32, 34 ] | ||
``` | ||
### `fork` the Fleuve | ||
*Warning: might become a static operator rather than a method of the Fleuve class* | ||
### Close a MutableObservable with `close` | ||
You can fork a Fleuve. The new Fleuve will still be connected to the original Fleuve, but with some pre-processing operations. | ||
```ts | ||
const obs$ = mutable(0); | ||
obs$.close(); | ||
``` | ||
## How to use ObservableForks | ||
### `fork` observables | ||
```ts | ||
const fleuve$ = new Fleuve(12); | ||
const forked$ = fleuve$.fork(filter(x => x > 15)); | ||
const obs$ = mutable(12); | ||
const forked$ = fork(obs$, filter(x => x > 15)); | ||
forked$.subscribe(x => console.log(x)); // nothing would happen at first | ||
fleuve$.next(20); // now, 20 would be printed in the browser's console | ||
obs$.next(20); // now, 20 would be printed in the browser's console | ||
``` | ||
### You can stop a Fleuve's forks with the `closeForks` method | ||
### Stop a fork | ||
No more values will be allowed and the forks will be flagged as complete. | ||
```ts | ||
const fleuve$ = new Fleuve(12); | ||
const fork1$ = fleuve$.fork(map(x => x * 2)); | ||
const fork2$ = fork1$.fork(filter(x => x < 100)); | ||
const obs$ = mutable(12); | ||
const fork1$ = fork(obs$, map(x => x * 2)); | ||
const fork2$ = fork(obs$, filter(x => x > 100)); | ||
fleuve$.closeForks(); | ||
fork1$.subscribe(x => console.log('fork1$ value', x)); // will display "24" | ||
fork2$.subscribe(x => console.log('fork2$ value', x)); // will display "24" | ||
const subscriber = subscriberOf((x) => console.log('fork1$ value', x), () => console.log('fork1 complete')); | ||
fork1$.subscribe(subscriber); // will display "24" | ||
fleuve$.next(99); // the forks' subscribers won't be triggered | ||
fork2$.subscribe((x) => console.log('fork2$ value', x)); // will display nothing | ||
obs$.close(); // will trigger fork1$'s complete callback | ||
obs$.next(99); // the forks' subscribers won't be triggered | ||
``` | ||
@@ -137,15 +149,30 @@ | ||
This operator allows you to create a Fleuve from a single scalar value. It creates a finite Fleuve with one or multiple scalar values. Once created, the Fleuve is automatically complete. | ||
This operator allows you to create an Observable from discrete values. It creates a finite Observable. Once created, the Observable is automatically complete. | ||
```ts | ||
const fleuve$ = of(12); | ||
fleuve$.subscribe(subscriberOf((x) => console.log(x))) | ||
const obs$ = of(12, 13, 14); | ||
obs$.subscribe(subscriberOf((x) => console.log(x))); // will display "12", "13", "14" | ||
``` | ||
#### `from` - static | ||
*This operator is static: it means your cannot use it as a parameter for methods such as `pipe` or `compile`* | ||
This operator works just like `of`, except it will take an array as a parameter, and flatten it. | ||
#### `mutable` - static | ||
*This operator is static: it means your cannot use it as a parameter for methods such as `pipe` or `compile`* | ||
This operator works just like `of`, except it will return a `MutableObservable` instead of an `Observable`. | ||
#### `mutableFrom` - static | ||
*This operator is static: it means your cannot use it as a parameter for methods such as `pipe` or `compile`* | ||
This operator works just like `from`, except it will return a `MutableObservable` instead of an `Observable`. | ||
#### `preProcess` - static | ||
*This operator is static: it means you cannot use it as a parameter for methods such as `pipe`, `compile` or `fork`*. | ||
*This operator is static: it means your cannot use it as a parameter for methods such as `pipe` or `compile`* | ||
This operator allows you to create a Fleuve bearing pre-processing operations. Those operations will execute every time you provide a new value to the Fleuve. | ||
This operator allows you to create a MutableObservable bearing pre-processing operations. Those operations will execute every time you provide a new value to the MutableObservable. | ||
It is useful if you want to connect to a source of data, and only retrieve those which match a predicate. | ||
It is useful if you want to connect to a source of data, and only retrieve those that match a predicate. | ||
@@ -155,10 +182,10 @@ In the following example, we assume we want to retrieve some stats about temperatures, and we would like to only retrieve entries where the temperature is > 30°C; | ||
```ts | ||
const fleuve$ = preProcess(filter(stat => stat.temp > 30)); | ||
const obs$ = preProcess(filter(stat => stat.temp > 30)); | ||
// displayStat is an arbitrary function we would have to implement | ||
fleuve$.subscribe(stat => displayStat(stat)); | ||
obs$.subscribe(stat => displayStat(stat)); | ||
fetch('someUrl') | ||
.then(res => res.json()) | ||
.then(stats => fleuve$.next(...stats)); | ||
.then(stats => obs$.next(...stats)); | ||
``` | ||
@@ -169,4 +196,4 @@ | ||
```ts | ||
const fleuve$ = new Fleuve(12); | ||
fleuve$.pipe(map(x => x * 2)).subscribe((value) => console.log(value)); // will display "24" | ||
const obs$ = of(12); | ||
obs$.pipe(map(x => x * 2)).subscribe((value) => console.log(value)); // will display "24" | ||
``` | ||
@@ -177,6 +204,6 @@ | ||
```ts | ||
const fleuve$ = new Fleuve(12); | ||
fleuve$.pipe(switchmap((x) => { | ||
const obs$ = of(12); | ||
obs$.pipe(switchmap((x) => { | ||
if (x > 0) { | ||
return new Fleuve(0); | ||
return of(0); | ||
} | ||
@@ -189,7 +216,5 @@ })); | ||
```ts | ||
const fleuve$ = new Fleuve(12); | ||
const filtered$ = fleuve$.pipe(filter(x => x > 10)); | ||
const obs$ = of(12, 0, -1, 100); | ||
const filtered$ = obs$.pipe(filter(x => x > 10)); | ||
filtered$.subscribe((value) => console.log(value)); // will display "12" and "100" | ||
filtered$.next(0); | ||
filtered$.next(100); | ||
``` | ||
@@ -199,7 +224,7 @@ #### `until` | ||
```ts | ||
const fleuve$ = preProcess(until(x => x >= 10)); | ||
fleuve$.subscribe((value) => console.log(value)); // will display 0, 1, ..., 9 | ||
const obs$ = preProcess(until(x => x >= 10)); | ||
obs$.subscribe((value) => console.log(value)); // will display 0, 1, ..., 9 | ||
for(let i = 0; i < 11; i++) { | ||
fleuve$.next(i); | ||
for(let i = 0; i < 100; i++) { | ||
obs$.next(i); | ||
} | ||
@@ -210,7 +235,7 @@ ``` | ||
```ts | ||
const fleuve$ = preProcess(asLongAs(x => x < 10)); | ||
fleuve$.subscribe((value) => console.log(value)); // will display 0, 1, ..., 9 | ||
const obs$ = preProcess(asLongAs(x => x < 10)); | ||
obs$.subscribe((value) => console.log(value)); // will display 0, 1, ..., 9 | ||
for(let i = 0; i < 11; i++) { | ||
fleuve$.next(i); | ||
obs$.next(i); | ||
} | ||
@@ -220,9 +245,9 @@ ``` | ||
#### `ifElse` | ||
The `ifElse` operator is pretty useful when it comes to add branches to a Fleuve. it can be used either on a `pipe`, `compile`, `fork` method or on a *creation operator* such as `preProcess`. | ||
The `ifElse` operator is pretty useful when it comes to add branches to an Observable. it can be used either on a `pipe` or `compile` method or on a *creation operator* such as `preProcess`. | ||
If the next example, we want to sort out some data and apply a different process according to each value. Values over 30 will trigger logging treatment, while others will just trigger an API call. | ||
In the next example, we want to sort out some data and apply a different process according to each value. Values over 30 will trigger logging treatment, while others will just trigger an API call. | ||
```ts | ||
const temperatures = [-15, 0, 12, 16, 30, 35, 45, -8]; | ||
const fleuve$ = preProcess( | ||
const obs$ = preProcess( | ||
ifElse((x) => x > 30, | ||
@@ -232,11 +257,11 @@ [tap((x) => logError(`Unexpected value: ${x}`))], | ||
); | ||
fleuve$.next(...temperatures); | ||
obs$.next(...temperatures); | ||
``` | ||
#### `tap` | ||
The `tap` operator is useful when it comes to trigger a treatment that won't affect the outcome of the `pipe` / `compile` / `fork` operation. | ||
The `tap` operator is useful when it comes to trigger a treatment that won't affect the outcome of the `pipe` / `compile` operation. | ||
```ts | ||
const fleuve$ = of(12); | ||
const piped$ = fleuve$.pipe(tap(x => console.log(x), map(x => x * 2))); // expected to print 12 | ||
const obs$ = of(12); | ||
const piped$ = obs$.pipe(tap(x => console.log(x), map(x => x * 2))); // expected to print 12 | ||
piped$.subscribe((x) => console.log(x)); // expected to print 24 | ||
@@ -306,6 +331,3 @@ ``` | ||
##### Creation | ||
- from: a finite Fleuve from a finite sequence | ||
- preProcess: an infinite Fleuve with zero or multiple pre-processing operations | ||
- infinite: an infinite Fleuve | ||
- compose: to compose finite and infinite Fleuve creators | ||
- compose: to compose finite and infinite Observable creators | ||
@@ -312,0 +334,0 @@ ##### Asynchronous |
@@ -7,2 +7,11 @@ export function isFunction(fn: any): fn is Function { | ||
return fns.filter((f) => isFunction(f)); | ||
} | ||
} | ||
/* istanbul ignore next */ | ||
export function fail(message: string = "", ...args: any[]) { | ||
const errorMsg = `Test failed\n${message} ${args.reduce( | ||
(acc, curr) => `${acc} ${curr}`, | ||
"" | ||
)}`; | ||
throw new Error(errorMsg); | ||
} |
@@ -1,2 +0,2 @@ | ||
export * from './fleuve/fleuve'; | ||
export * from './operators/index'; | ||
export * from './observable'; | ||
export * from './operators'; |
export type OperatorFunction<T, U = never> = (source: T) => U; | ||
export class OperationResult<T> { | ||
constructor(private _value: T, private _flag?: OperationResultFlag) {} | ||
constructor(private _value: T, private _flag?: OperationResultFlag, private _error?: Error) {} | ||
@@ -14,2 +14,6 @@ get value() { | ||
get error() { | ||
return this._error; | ||
} | ||
isUnwrapSwitch(): boolean { | ||
@@ -26,8 +30,13 @@ return this._flag === OperationResultFlag.UnwrapSwitch; | ||
} | ||
isOperationError(): boolean { | ||
return this._flag === OperationResultFlag.OperationError | ||
} | ||
} | ||
export enum OperationResultFlag { | ||
UnwrapSwitch, | ||
MustStop, | ||
FilterNotMatched | ||
UnwrapSwitch = 'UnwrapSwitch', | ||
MustStop = 'MustStop', | ||
FilterNotMatched = 'FilterNotMatched', | ||
OperationError = 'OperationError', | ||
} |
@@ -1,11 +0,13 @@ | ||
import { Fleuve } from "../fleuve/fleuve"; | ||
import { subscriberOf } from "./subscription"; | ||
import { MutableObservable } from "../observable/mutable-observable"; | ||
import { EMPTY_SUBSCRIPTION, subscriberOf, Subscription } from "./subscription"; | ||
describe('Subscription', () => { | ||
it('unsubscribe - should unsubscribe from a Fleuve', () => { | ||
const fleuve = new Fleuve(); | ||
it('will succeed', () => expect(true).toBe(true)); | ||
it('unsubscribe - should unsubscribe from a Observable', () => { | ||
const observable = new MutableObservable(); | ||
const shouldNotBeCalled = jest.fn(); | ||
const subscription = fleuve.subscribe(() => shouldNotBeCalled()); | ||
const subscription = observable.subscribe(() => shouldNotBeCalled()); | ||
subscription.unsubscribe(); | ||
fleuve.next(); | ||
observable.next(); | ||
expect(shouldNotBeCalled).not.toHaveBeenCalled(); | ||
@@ -19,5 +21,10 @@ }); | ||
} catch(err) { | ||
expect(err).toEqual(new Error(`Please provide functions for onNext, onError and onComplete`)); | ||
expect(err).toEqual(new Error(`Please provide functions for next, error and complete`)); | ||
} | ||
}); | ||
it('should be an empty Subscription', () => { | ||
const emptySub = new Subscription(); | ||
expect(EMPTY_SUBSCRIPTION).toEqual(emptySub); | ||
}) | ||
}); |
import { isFunction } from "../helpers/function.helper"; | ||
export class Subscription { | ||
constructor(private _unsubscribeCallback: UnsubscribeCallback) {} | ||
constructor(private _unsubscribeCallback?: UnsubscribeCallback) {} | ||
unsubscribe(): void { | ||
this._unsubscribeCallback(); | ||
this._unsubscribeCallback && this._unsubscribeCallback(); | ||
} | ||
} | ||
export const EMPTY_SUBSCRIPTION = new Subscription(); | ||
interface UnsubscribeCallback { | ||
@@ -15,14 +17,18 @@ (): void | ||
export interface Subscriber<T = any> { | ||
next: OnNext<T>, error?: OnError, complete?: OnComplete<T> | ||
next?: OnNext<T>, error?: OnError, complete?: OnComplete | ||
} | ||
export function isInstanceOfSubscriber(obj: any): obj is Subscriber { | ||
return isFunction(obj.next) && (obj.error === undefined || isFunction(obj.error)) && (obj.complete == undefined || isFunction(obj.complete)); | ||
function hasAtLeastOneOfTheseFieldsAsAFunction(obj: {[k: string]: any}, ...fields: string[]): boolean { | ||
return fields.some(field => obj[field] !== undefined && obj[field] !== null && isFunction(obj[field])); | ||
} | ||
return !isFunction(obj) && hasAtLeastOneOfTheseFieldsAsAFunction(obj, 'next', 'error', 'complete'); | ||
} | ||
export function subscriberOf<T>(next: OnNext<T>, error?: OnError, complete?: OnComplete<T>): Subscriber<T> { | ||
if (!isInstanceOfSubscriber({next, error, complete})) { | ||
throw new Error(`Please provide functions for onNext, onError and onComplete`); | ||
export function subscriberOf<T>(next?: OnNext<T>, error?: OnError, complete?: OnComplete): Subscriber<T> { | ||
const subscriber: Subscriber<T> = {next, error, complete}; | ||
if (!isInstanceOfSubscriber(subscriber)) { | ||
throw new Error(`Please provide functions for next, error and complete`); | ||
} | ||
return {next, error, complete}; | ||
return subscriber; | ||
} | ||
@@ -39,5 +45,5 @@ | ||
export interface OnComplete<T> { | ||
(result: T | Error | undefined): void | ||
export interface OnComplete { | ||
(): void | ||
}; | ||
export * from './predicates'; | ||
export * from './transform'; | ||
export * from './transform'; | ||
export * from './side-effects'; | ||
export * from './static'; |
@@ -1,2 +0,2 @@ | ||
import { Fleuve } from "../../fleuve/fleuve"; | ||
import { Observable } from "../../observable/observable"; | ||
import { map } from "../transform/map"; | ||
@@ -6,16 +6,18 @@ import {ifElse} from './if-else'; | ||
describe('ifElse', () => { | ||
it('should return a new fleuve from the "if" branch', () => { | ||
const fleuve$ = new Fleuve(12); | ||
const res$ = fleuve$.pipe(ifElse((x) => x > 0, [map(x => x * 2)])); | ||
it('will succeed', () => expect(true).toBe(true)); | ||
it('should return a new observable from the "if" branch', () => { | ||
const obs$ = new Observable(12); | ||
const res$ = obs$.pipe(ifElse((x) => x > 0, [map(x => x * 2)])); | ||
res$.subscribe((x) => expect(x).toEqual(24)); | ||
}); | ||
it('should return a new fleuve from the "else" branch', () => { | ||
const fleuve$ = new Fleuve(120); | ||
const res$ = fleuve$.pipe(ifElse((x) => x < 100, [map(x => x * 2)], [map(() => 100)])); | ||
it('should return a new observable from the "else" branch', () => { | ||
const obs$ = new Observable(120); | ||
const res$ = obs$.pipe(ifElse((x) => x < 100, [map(x => x * 2)], [map(() => 100)])); | ||
res$.subscribe((x) => expect(x).toEqual(100)); | ||
const res2$ = fleuve$.pipe(ifElse((x) => x < 100, [map(x => x * 2)])); | ||
const res2$ = obs$.pipe(ifElse((x) => x < 100, [map(x => x * 2)])); | ||
res2$.subscribe((x) => expect(x).toEqual(120)); | ||
}); | ||
}); |
@@ -1,8 +0,5 @@ | ||
import { Fleuve } from "../../fleuve/fleuve"; | ||
import { | ||
OperatorFunction, | ||
OperationResult, | ||
OperationResultFlag, | ||
} from "../../models/operator"; | ||
import { of } from "../static/creation/of"; | ||
import { filter } from "./filter"; | ||
@@ -14,12 +11,13 @@ | ||
elses?: OperatorFunction<T, OperationResult<U>>[] | ||
): OperatorFunction<T, OperationResult<Fleuve<U>>> { | ||
): OperatorFunction<T, OperationResult<U | T>> { | ||
return (source: T) => { | ||
const operationResult = filter(predicate)(source); | ||
return new OperationResult( | ||
!operationResult.isFilterNotMatched() | ||
? of(source).pipe(...ifs) | ||
: of(source).pipe(...(elses ?? [])), | ||
OperationResultFlag.UnwrapSwitch | ||
); | ||
const operators = !operationResult.isFilterNotMatched() ? ifs : (elses ?? []); | ||
const start = operators.shift(); | ||
if (start) { | ||
return operators.reduce((acc, curr) => curr(acc.value as any), start(source)); | ||
} | ||
return operationResult; | ||
}; | ||
}; |
@@ -0,3 +1,4 @@ | ||
export * from './as-long-as'; | ||
export * from './filter'; | ||
export * from './as-long-as'; | ||
export * from './if-else'; | ||
export * from './until'; |
import {of} from './of'; | ||
describe('of', () => { | ||
it('should create a new Fleuve', () => { | ||
const fleuve$ = of(12); | ||
it('will succeed', () => expect(true).toBe(true)); | ||
it('should create a new Observable', () => { | ||
const obs$ = of(12); | ||
const spy = jest.fn(); | ||
fleuve$.subscribe({next: (x) => expect(x).toEqual(12), complete: () => spy()}); | ||
obs$.subscribe({next: (x) => expect(x).toEqual(12), complete: () => spy()}); | ||
expect(spy).toHaveBeenCalledTimes(1); | ||
}); | ||
}); |
@@ -1,8 +0,5 @@ | ||
import { Fleuve } from "../../../fleuve/fleuve"; | ||
import { Observable } from "../../../observable"; | ||
export const of = function<T>(value: T): Fleuve<T> { | ||
const fleuve$ = new Fleuve(value); | ||
fleuve$.close(); | ||
(fleuve$ as any)._isFinite = true; | ||
return fleuve$; | ||
export const of = function<T = never>(...values: T[]): Observable<T> { | ||
return new Observable(...values); | ||
} |
@@ -1,2 +0,2 @@ | ||
import { Fleuve } from '../../../fleuve/fleuve'; | ||
import { Observable } from '../../../observable/observable'; | ||
import { until } from '../../predicates/until'; | ||
@@ -7,14 +7,16 @@ import { map } from '../../transform/map'; | ||
describe('preProcess', () => { | ||
it('should return a new Fleuve', () => { | ||
expect(preProcess()).toBeInstanceOf(Fleuve); | ||
it('will succeed', () => expect(true).toBe(true)); | ||
it('should return a new Observable', () => { | ||
expect(preProcess()).toBeInstanceOf(Observable); | ||
}); | ||
it('should apply the pre-processing operations every time we next', () => { | ||
const fleuve$ = preProcess<number>(map(x => x * 2), until(x => x >= 100)); | ||
const obs$ = preProcess<number>(map(x => x * 2), until(x => x >= 100)); | ||
let i = 0; | ||
fleuve$.subscribe(x => (i < 100 ? expect(x).toEqual(i * 2) : expect(x).toEqual(50))); | ||
obs$.subscribe(x => (i < 100 ? expect(x).toEqual(i * 2) : expect(x).toEqual(50))); | ||
for(; i < 200; i++) { fleuve$.next(i); } | ||
for(; i < 200; i++) { obs$.next(i); } | ||
}); | ||
}) |
@@ -1,8 +0,8 @@ | ||
import { Fleuve } from "../../../fleuve/fleuve"; | ||
import { OperationResult, OperatorFunction } from "../../../models/operator"; | ||
import { MutableObservable } from "../../../observable"; | ||
export function preProcess<T = never>(...operations: OperatorFunction<any, OperationResult<T>>[]): Fleuve<T> { | ||
const fleuve$ = new Fleuve<T>(); | ||
(fleuve$ as any)._preProcessOperations.push(...operations); | ||
return fleuve$; | ||
export function preProcess<T = never>(...operations: OperatorFunction<any, OperationResult<T>>[]): MutableObservable<T> { | ||
const obs$ = new MutableObservable<T>(); | ||
(obs$ as any)._preProcessOperations.push(...operations); | ||
return obs$; | ||
} |
import { map } from "./map"; | ||
describe("Operators", () => { | ||
describe("map", () => { | ||
@@ -5,0 +6,0 @@ it("should return a new function to apply the mapping", () => { |
@@ -1,16 +0,27 @@ | ||
import { Fleuve } from "../../fleuve/fleuve"; | ||
import { Observable } from "../../observable/observable"; | ||
import { of } from "../static"; | ||
import { switchMap } from "./switch-map"; | ||
describe('switchMap', () => { | ||
it('will succeed', () => expect(true).toBe(true)); | ||
it('should return a new function to apply the switch', () => { | ||
let _innerSource: any = 12; | ||
const switchMappedFct = switchMap((x) => new Fleuve(x * 2)); | ||
expect(switchMappedFct(_innerSource).value).toEqual(new Fleuve(24)); | ||
const switchMappedFct = switchMap((x) => new Observable(x * 2)); | ||
expect(switchMappedFct(_innerSource).value).toEqual(new Observable(24)); | ||
expect(switchMappedFct(_innerSource).isUnwrapSwitch()).toEqual(true); | ||
_innerSource = {firstname: 'John', lastname: 'DOE'}; | ||
const fullnameFct = switchMap(({firstname, lastname}) => new Fleuve(`${firstname} ${lastname}`)); | ||
expect(fullnameFct(_innerSource).value).toEqual(new Fleuve('John DOE')); | ||
const fullnameFct = switchMap(({firstname, lastname}) => new Observable(`${firstname} ${lastname}`)); | ||
expect(fullnameFct(_innerSource).value).toEqual(new Observable('John DOE')); | ||
expect(switchMappedFct(_innerSource).isUnwrapSwitch()).toEqual(true); | ||
}); | ||
it("should return a new Observable", () => { | ||
const obs$ = of(12); | ||
const pipedobs$ = obs$.pipe( | ||
switchMap((x: number) => of(x * 2)) | ||
); | ||
pipedobs$.subscribe((value) => expect(value).toEqual(24)); | ||
}); | ||
}); |
@@ -1,2 +0,1 @@ | ||
import { Fleuve } from "../../fleuve/fleuve"; | ||
import { | ||
@@ -7,7 +6,8 @@ OperationResult, | ||
} from "../../models/operator"; | ||
import { Observable } from "../../observable/observable"; | ||
export function switchMap<T = any, U = T>( | ||
f: OperatorFunction<T, Fleuve<U>> | ||
): OperatorFunction<T, OperationResult<Fleuve<U>>> { | ||
f: OperatorFunction<T, Observable<U>> | ||
): OperatorFunction<T, OperationResult<Observable<U>>> { | ||
return (source: T) => new OperationResult(f(source), OperationResultFlag.UnwrapSwitch); | ||
} |
@@ -1,4 +0,4 @@ | ||
import { Fleuve } from '../../bundle/fleuve.bundle.js'; | ||
import { MutableObservable } from '../../bundle/observable.bundle.js'; | ||
const counter$ = new Fleuve(0); | ||
const counter$ = new MutableObservable(0); | ||
const counter = document.getElementById('counter'); | ||
@@ -5,0 +5,0 @@ |
@@ -1,7 +0,7 @@ | ||
import {Fleuve, map, filter} from '../../bundle/fleuve.bundle.js'; | ||
import {MutableObservable, filter} from '../../bundle/observable.bundle.js'; | ||
const result = document.getElementById('results'); | ||
const fleuve$ = new Fleuve(12); | ||
const forked$ = fleuve$.fork(filter(x => x > 15)); | ||
const obs$ = new MutableObservable(12); | ||
const forked$ = obs$.fork(filter(x => x > 15)); | ||
forked$.subscribe(x => result.innerText += `${x}\n`); // nothing would happen at first | ||
fleuve$.next(20); // now, 20 would be printed in the browser's console | ||
obs$.next(20); // now, 20 would be printed in the browser's console |
@@ -1,10 +0,10 @@ | ||
import {Fleuve, map, filter} from '../../bundle/fleuve.bundle.js'; | ||
import {Observable, map, filter} from '../../bundle/observable.bundle.js'; | ||
const result = document.getElementById('results'); | ||
const fleuve$ = new Fleuve(12); | ||
const obs$ = new Observable(12); | ||
fleuve$.pipe(map(x => x * 2)).subscribe((value) => result.innerText += `Mapped value is ${value}`); | ||
fleuve$.pipe(filter(x => x > 1000)).subscribe((value) => result.innerText += `\nFiltered value is ${value}`); | ||
fleuve$.pipe(map(x => x * 2), filter(x => x > 12)).subscribe((value) => result.innerText += `\nMapped then filtered value is ${value}`); | ||
fleuve$.pipe(map(x => x * 2), filter(x => x < 12)).subscribe((value) => result.innerText += `\nMapped then filtered value (bis) is ${value}`); | ||
obs$.pipe(map(x => x * 2)).subscribe((value) => result.innerText += `Mapped value is ${value}`); | ||
obs$.pipe(filter(x => x > 1000)).subscribe((value) => result.innerText += `\nFiltered value is ${value}`); | ||
obs$.pipe(map(x => x * 2), filter(x => x > 12)).subscribe((value) => result.innerText += `\nMapped then filtered value is ${value}`); | ||
obs$.pipe(map(x => x * 2), filter(x => x < 12)).subscribe((value) => result.innerText += `\nMapped then filtered value (bis) is ${value}`); |
@@ -9,3 +9,3 @@ const path = require("path"); | ||
output: { | ||
filename: "fleuve.bundle.js", | ||
filename: "observable.bundle.js", | ||
path: path.resolve(__dirname, "bundle"), | ||
@@ -12,0 +12,0 @@ library: { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
109688
121
2005
337
1