From cf273ef9cfdbc92659f27cc15d24f84e2a7c8c8a Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Sat, 13 Aug 2022 14:22:13 +0100 Subject: [PATCH] Update docs for TS-only --- README.md | 21 +-- docs/api/operators.md | 365 ++++-------------------------------- docs/api/sinks.md | 100 +--------- docs/api/sources.md | 163 ++-------------- docs/basics/architecture.md | 54 +++--- docs/index.md | 21 +-- docs/migration.md | 17 ++ gatsby/theme.css | 30 --- gatsby/theme.js | 50 ----- gatsby/typography.js | 15 -- 10 files changed, 112 insertions(+), 724 deletions(-) delete mode 100644 gatsby/theme.css delete mode 100644 gatsby/theme.js delete mode 100644 gatsby/typography.js diff --git a/README.md b/README.md index 84a2cf4..dfd3460 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # Wonka -A fast push & pull stream library for Reason, loosely following the [callbag spec](https://github.com/callbag/callbag) +A tiny but capable push & pull stream library for TypeScript and Flow, +loosely following the [callbag spec](https://github.com/callbag/callbag) -> **NOTE:** The `master` branch currently points to the v4 Release Candidate version! -> If you're looking for v3, [please check the `v3.2.2`](https://github.com/kitten/wonka/tree/v3.2.2) +> **NOTE:** The currently released version v6 is only compatible now with TypeScript, Flow, and JavaScript. +> If you're looking for Reason/OCaml/esy/dune support, please check v5, and if you're looking for the legacy version +> of this library check v4.
@@ -34,19 +36,6 @@ the [callbag spec](https://github.com/callbag/callbag). It exposes a set of help which are sources of multiple values, which allow you to create, transform and consume event streams or iterable sets of data. -Wonka is written in [Reason](https://reasonml.github.io/), a dialect of OCaml, and can hence be used -for native applications. It is also compiled using [BuckleScript](https://bucklescript.github.io) to plain -JavaScript and has typings for [TypeScript](https://www.typescriptlang.org/) and [Flow](https://flow.org/). - -This means that out of the box Wonka is usable in any project that use the following: - -- Plain JavaScript -- TypeScript -- Flow -- Reason/OCaml with BuckleScript -- Reason/OCaml with `bs-native` -- Reason/OCaml with Dune and Esy - ## [Documentation](https://wonka.kitten.sh/) **See the documentation at [wonka.kitten.sh](https://wonka.kitten.sh)** for more information about using `wonka`! diff --git a/docs/api/operators.md b/docs/api/operators.md index 1557dfb..2b09a40 100644 --- a/docs/api/operators.md +++ b/docs/api/operators.md @@ -15,26 +15,15 @@ be sent when a notifier fires and will be arrays of all items before the notific In combination with `interval` this can be used to group values in chunks regularly. -```reason -Wonka.interval(50) - |> Wonka.buffer(Wonka.interval(100)) - |> Wonka.take(2) - |> Wonka.subscribe((. buffer) => { - Js.Array.forEach(num => print_int(num), buffer); - print_endline(";"); - }); -/* Prints 1 2; 2 3 to the console. */ -``` - -``` typescript +```typescript import { pipe, interval, buffer, take, subscribe } from 'wonka'; pipe( interval(50), buffer(interval(100)), take(2), - subscribe(buffer => { - buffer.forEach(x => console.log(x)); + subscribe((buffer) => { + buffer.forEach((x) => console.log(x)); console.log(';'); }) ); // Prints 1 2; 2 3 to the console. @@ -44,17 +33,6 @@ pipe( `combine` two sources together to a single source. The emitted value will be a combination of the two sources, with all values from the first source being emitted with the first value of the second source _before_ values of the second source are emitted. -```reason -let sourceOne = Wonka.fromArray([|1, 2, 3|]); -let sourceTwo = Wonka.fromArray([|4, 5, 6|]); - -Wonka.combine(sourceOne) - |> sourceTwo - |> Wonka.subscribe((. (a, b)) => print_int(a + b)); - -/* Prints 56789 (1+4, 2+4, 3+4, 3+5, 3+6) to the console. */ -``` - ```typescript import { fromArray, pipe, combine, subscribe } from 'wonka'; @@ -73,15 +51,6 @@ pipe( `concat` will combine two sources together, subscribing to the next source after the previous source completes. -```reason -let sourceOne = Wonka.fromArray([|1, 2, 3|]); -let sourceTwo = Wonka.fromArray([|6, 5, 4|]); - -Wonka.concat([|sourceOne, sourceTwo|]) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 1 2 3 6 5 4 to the console. */ -``` - ```typescript import { fromArray, pipe, concat, subscribe } from 'wonka'; @@ -90,7 +59,7 @@ const sourceTwo = fromArray([6, 5, 4]); pipe( concat([sourceOne, sourceTwo]), - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); // Prints 1 2 3 6 5 4 to the console. ``` @@ -101,16 +70,6 @@ next source after the previous source completes. It's very similar to `concat`, but instead accepts a source of sources as an input. -```reason -let sourceOne = Wonka.fromArray([|1, 2, 3|]); -let sourceTwo = Wonka.fromArray([|6, 5, 4|]); - -Wonka.fromList([sourceOne, sourceTwo]) - |> Wonka.concatAll - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 1 2 3 6 5 4 to the console. */ -``` - ```typescript import { pipe, fromArray, concatAll, subscribe } from 'wonka'; @@ -120,7 +79,7 @@ const sourceTwo = fromArray([6, 5, 4]); pipe( fromArray([sourceOne, sourceTwo]), concatAll, - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); // Prints 1 2 3 6 5 4 to the console. ``` @@ -128,20 +87,6 @@ pipe( `concatMap` allows you to map values of an outer source to an inner source. The sink will not dispatch the `Pull` signal until the previous value has been emitted. This is in contrast to `mergeMap`, which will dispatch the `Pull` signal for new values even if the previous value has not yet been emitted. -```reason -let source = Wonka.fromArray([|1, 2, 3, 4, 5, 6|]); - -source -|> Wonka.concatMap((. _val) => - Wonka.delay(_val * 1000, Wonka.fromValue(_val)) - ) -|> Wonka.subscribe((. _val) => print_int(_val)); - -/* After 1s, 1 will be emitted. After an additional 2s, 2 will be emitted. -After an additional 3s, 3 will be emitted. After an additional 4s, 4 will be emitted. -After an additional 5s, 5 will be emitted. After an additional 6s, 6 will be emitted. */ -``` - ```typescript import { fromArray, pipe, concatMap, delay, fromValue, subscribe } from 'wonka'; @@ -149,31 +94,17 @@ const source = fromArray([1, 2, 3, 4, 5, 6]); pipe( source, - concatMap(val => { - return pipe( - fromValue(val), - delay(val * 1000) - ); + concatMap((val) => { + return pipe(fromValue(val), delay(val * 1000)); }), - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); ``` - ## delay `delay` delays all emitted values of a source by the given amount of milliseconds. -> _Note:_ This operator is only available in JavaScript environments, and will be excluded -> when compiling natively. - -```reason -Wonka.fromList([1, 2]) - |> Wonka.delay(10) - |> Wonka.subscribe((. x) => print_int(x)); -/* waits 10ms then prints 1, waits 10ms then prints 2, waits 10ms then ends */ -``` - ```typescript import { pipe, fromArray, delay, subscribe } from 'wonka'; @@ -191,21 +122,6 @@ pipe( a given amount of milliseconds. Once this threshold of silence has been reached, the last value that has been received will be emitted. -> _Note:_ This operator is only available in JavaScript environments, and will be excluded -> when compiling natively. - -```reason -let sourceA = Wonka.interval(10) - |> Wonka.take(5); -let sourceB = Wonka.fromValue(1); - -Wonka.concat([|sourceA, sourceB|]) - |> Wonka.debounce((. _x) => 20) - |> Wonka.subscribe((. x) => print_int(x)); -/* The five values from sourceA will be omitted */ -/* After these values and after 20ms `1` will be logged */ -``` - ```typescript import { pipe, interval, take, fromValue, concat, debounce, subscribe } from 'wonka'; @@ -226,24 +142,15 @@ pipe( `filter` will remove values from a source by passing them through an iteratee that returns a `bool`. -```reason -let isEven = (. n) => n mod 2 === 0; - -Wonka.fromArray([|1, 2, 3, 4, 5, 6|]) - |> Wonka.filter(isEven) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 246 to the console. */ -``` - ```typescript import { fromArray, filter, subscribe } from 'wonka'; -const isEven = n => n % 2 === 0; +const isEven = (n) => n % 2 === 0; pipe( fromArray([1, 2, 3, 4, 5, 6]), filter(isEven), - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); // Prints 246 to the console. @@ -253,24 +160,15 @@ pipe( `map` will transform values from a source by passing them through an iteratee that returns a new value. -```reason -let square = (. n) => n * n; - -Wonka.fromArray([|1, 2, 3, 4, 5, 6|]) - |> Wonka.map(square) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 1 4 9 16 25 36 to the console. */ -``` - ```typescript import { fromArray, pipe, map, subscribe } from 'wonka'; -const square = n => n * n; +const square = (n) => n * n; pipe( fromArray([1, 2, 3, 4, 5, 6]), map(square), - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); // Prints 1 4 9 16 25 36 to the console. @@ -281,15 +179,6 @@ pipe( `merge` merges an array of sources together into a single source. It subscribes to all sources that it's passed and emits all their values on the output source. -```reason -let sourceA = Wonka.fromArray([|1, 2, 3|]); -let sourceB = Wonka.fromArray([|4, 5, 6|]); - -Wonka.merge([|sourceA, sourceB|]) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 1 2 3 4 5 6 to the console. */ -``` - ```typescript import { fromArray, pipe, merge, subscribe } from 'wonka'; @@ -309,16 +198,6 @@ It's very similar to `merge`, but instead accepts a source of sources as an inpu > _Note:_ This operator is also exported as `flatten` which is just an alias for `mergeAll` -```reason -let sourceA = Wonka.fromArray([|1, 2, 3|]); -let sourceB = Wonka.fromArray([|4, 5, 6|]); - -Wonka.fromList([sourceA, sourceB]) - |> Wonka.mergeAll - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 1 2 3 4 5 6 to the console. */ -``` - ```typescript import { pipe, fromArray, mergeAll, subscribe } from 'wonka'; @@ -328,7 +207,7 @@ const sourceTwo = fromArray([4, 5, 6]); pipe( fromArray([sourceOne, sourceTwo]), mergeAll, - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); // Prints 1 2 3 4 5 6 to the console. ``` @@ -341,21 +220,13 @@ all be merged into a single source, like with `mergeAll`. Unlike `concatMap` all inner sources will be subscribed to at the same time and all their values will be emitted on the output source as they come in. -```reason -Wonka.fromList([1, 2]) - |> Wonka.mergeMap((. value) => - Wonka.fromList([value - 1, value])) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 0 1 1 2 to the console. */ -``` - ```typescript import { pipe, fromArray, mergeMap, subscribe } from 'wonka'; pipe( fromArray([1, 2]), - mergeMap(x => fromArray([x - 1, x])), - subscribe(val => console.log(val)) + mergeMap((x) => fromArray([x - 1, x])), + subscribe((val) => console.log(val)) ); // Prints 0 1 1 2 to the console. ``` @@ -363,36 +234,15 @@ pipe( Run a callback when the `End` signal has been sent to the sink by the source, whether by way of the talkback passing the `End` signal or the source being exhausted of values. -```reason -let promiseOne = - Js.Promise.make((~resolve, ~reject as _) => - Js.Global.setTimeout(() => resolve(. "ResolveOne"), 1000) |> ignore - ); - -let promiseTwo = - Js.Promise.make((~resolve, ~reject as _) => - Js.Global.setTimeout(() => resolve(. "ResolveTwo"), 2000) |> ignore - ); - -let sourceOne = Wonka.fromPromise(promiseOne); -let sourceTwo = Wonka.fromPromise(promiseTwo); - -Wonka.concat([|sourceOne, sourceTwo|]) - |> Wonka.onEnd((.) => print_endline("onEnd")) - |> Wonka.subscribe((. x) => print_endline(x)); - -/* Logs ResolveOne after one second, then ResolveTwo after an additional second, then onEnd immediately. */ -``` - ```typescript import { fromPromise, pipe, concat, onEnd, subscribe } from 'wonka'; -const promiseOne = new Promise(resolve => { +const promiseOne = new Promise((resolve) => { setTimeout(() => { resolve('ResolveOne'); }, 1000); }); -const promiseTwo = new Promise(resolve => { +const promiseTwo = new Promise((resolve) => { setTimeout(() => { resolve('ResolveTwo'); }, 2000); @@ -404,7 +254,7 @@ const sourceTwo = fromPromise(promiseTwo); pipe( concat([sourceOne, sourceTwo]), onEnd(() => console.log('onEnd')), - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); // Logs ResolveOne after one second, then ResolveTwo after an additional second, then onEnd immediately. @@ -416,20 +266,13 @@ Run a callback on each `Push` signal sent to the sink by the source. > _Note:_ This operator is also exported as `tap` which is just an alias for `onPush` -```reason -Wonka.fromArray([|1, 2, 3, 4, 5, 6|]) - |> Wonka.onPush((. x) => print_string({j|Push $x|j})) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints Push 1 1 Push 2 2 Push 3 3 Push 4 4 Push 5 5 Push 6 6 to the console. */ -``` - ```typescript import { fromArray, pipe, onPush, subscribe } from 'wonka'; pipe( fromArray([1, 2, 3, 4, 5, 6]), - onPush(val => console.log(`Push ${val}`)), - subscribe(val => console.log(val)) + onPush((val) => console.log(`Push ${val}`)), + subscribe((val) => console.log(val)) ); // Prints Push 1 1 Push 2 2 Push 3 3 Push 4 4 Push 5 5 Push 6 6 to the console. ``` @@ -437,23 +280,10 @@ pipe( Run a callback when the `Start` signal is sent to the sink by the source. -```reason -let promise = - Js.Promise.make((~resolve, ~reject as _) => - Js.Global.setTimeout(() => resolve(. "Resolve"), 1000) |> ignore - ); - -Wonka.fromPromise(promise) - |> Wonka.onStart((.) => print_endline("onStart")) - |> Wonka.subscribe((. _val) => print_endline(_val)); -/* Logs onStart to the console, pauses for one second to allow the timeout to finish, -then logs "Resolve" to the console. */ -``` - ```typescript import { pipe, onStart, fromPromise, subscribe } from 'wonka'; -const promise = new Promise(resolve => { +const promise = new Promise((resolve) => { setTimeout(() => { resolve('Resolve'); }, 1000); @@ -462,7 +292,7 @@ const promise = new Promise(resolve => { pipe( fromPromise(promise), onStart(() => console.log('onStart')), - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); // Logs onStart to the console, pauses for one second to allow the timeout to finish, @@ -477,22 +307,14 @@ an inner source (notifier) emits. In combination with `interval` it can be used to get values from a noisy source more regularly. -```reason -Wonka.interval(10) - |> Wonka.sample(Wonka.interval(100)) - |> Wonka.take(2) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 10 20 to the console. */ -``` - -``` typescript +```typescript import { pipe, interval, sample, take, subscribe } from 'wonka'; pipe( interval(10), sample(interval(100)), take(2), - subscribe(x => console.log(x)) + subscribe((x) => console.log(x)) ); // Prints 10 20 to the console. ``` @@ -500,20 +322,13 @@ pipe( Accumulate emitted values of a source in a accumulator, similar to JavaScript `reduce`. -```reason -Wonka.fromArray([|1, 2, 3, 4, 5, 6|]) - |> Wonka.scan((. acc, x) => acc + x, 0) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 1 3 6 10 15 21 to the console. */ -``` - ```typescript import { fromArray, pipe, scan, subscribe } from 'wonka'; pipe( fromArray([1, 2, 3, 4, 5, 6]), scan((acc, val) => acc + val, 0), - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); // Prints 1 3 6 10 15 21 to the console. @@ -536,16 +351,6 @@ listening to it anymore. This is especially useful if you introduce side-effects to your sources, for instance with `onStart`. -```reason -let source = Wonka.never - |> Wonka.onStart((.) => print_endline("start")) - |> Wonka.share; - -/* Without share this would print "start" twice: */ -Wonka.publish(source); -Wonka.publish(source); -``` - ```typescript import { pipe, never, onStart, share, publish } from 'wonka'; @@ -564,20 +369,13 @@ publish(source); `skip` the specified number of emissions from the source. -```reason -Wonka.fromArray([|1, 2, 3, 4, 5, 6|]) - |> Wonka.skip(2) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 3 4 5 6 to the console, since the first two emissions from the source were skipped. -``` - ```typescript import { fromArray, pipe, skip, subscribe } from 'wonka'; pipe( fromArray([1, 2, 3, 4, 5, 6]), skip(2), - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); ``` @@ -585,18 +383,6 @@ pipe( Skip emissions from an outer source until an inner source (notifier) emits. -```reason -let source = Wonka.interval(100); -let notifier = Wonka.interval(500); - -source - |> Wonka.skipUntil(notifier) - |> Wonka.subscribe((. x) => print_int(x)); - -/* Skips all values emitted by source (0, 1, 2, 3) until notifier emits at 500ms. -Then logs 4 5 6 7 8 9 10... to the console every 500ms. */ -``` - ```typescript import { interval, pipe, skipUntil, subscribe } from 'wonka'; @@ -606,7 +392,7 @@ const notifier = interval(500); pipe( source, skipUntil(notifier), - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); // Skips all values emitted by source (0, 1, 2, 3) until notifier emits at 500ms. @@ -617,23 +403,13 @@ pipe( Skip values emitted from the source while they return `true` for the provided predicate function. -```reason -let source = Wonka.fromArray([|1, 2, 3, 4, 5, 6|]); - -source -|> Wonka.skipWhile((. _val) => _val < 5) -|> Wonka.subscribe((. _val) => print_int(_val)); - -/* Prints 5 6 to the console, as 1 2 3 4 all return true for the predicate function. */ -``` - ```typescript import { fromArray, pipe, skipWhile, subscribe } from 'wonka'; pipe( fromArray([1, 2, 3, 4, 5, 6]), - skipWhile(val => val < 5), - subscribe(val => console.log(val)) + skipWhile((val) => val < 5), + subscribe((val) => console.log(val)) ); // Prints 5 6 to the console, as 1 2 3 4 all return true for the predicate function. @@ -650,25 +426,15 @@ from. This is similar to `concatMap` but instead of waiting for the last inner source to complete before emitting values from the next, `switchMap` just cancels the previous inner source. -```reason -Wonka.interval(50) - |> Wonka.switchMap((. _value) => - Wonka.interval(40)) - |> Wonka.take(3) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 1 2 3 to the console. */ -/* The inner interval is cancelled after its first value every time */ -``` - ```typescript import { pipe, interval, switchMap, take, subscribe } from 'wonka'; pipe( interval(50), // The inner interval is cancelled after its first value every time - switchMap(value => interval(40)), + switchMap((value) => interval(40)), take(3), - subscribe(x => console.log(x)) + subscribe((x) => console.log(x)) ); // Prints 1 2 3 to the console ``` @@ -680,16 +446,6 @@ ended while the next inner source is created. It's very similar to `switchMap`, but instead accepts a source of sources. -```reason -Wonka.interval(50) - |> Wonka.map((. _value) => - Wonka.interval(40)) - |> Wonka.switchAll - |> Wonka.take(3) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 1 2 3 to the console. */ -``` - ```typescript import { pipe, interval, map, switchAll, take, subscribe } from 'wonka'; @@ -698,7 +454,7 @@ pipe( map(() => interval(40)), switchAll, take(3), - subscribe(x => console.log(x)) + subscribe((x) => console.log(x)) ); // Prints 1 2 3 to the console ``` @@ -710,20 +466,13 @@ that `map` was used instead of using `switchMap` directly. This is because combi `take` only a specified number of emissions from the source before completing. `take` is the opposite of `skip`. -```reason -Wonka.fromArray([|1, 2, 3, 4, 5, 6|]) - |> Wonka.take(3) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 1 2 3 to the console. */ -``` - ```typescript import { fromArray, pipe, take, subscribe } from 'wonka'; pipe( fromArray([1, 2, 3, 4, 5, 6]), take(3), - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); // Prints 1 2 3 to the console. @@ -733,20 +482,13 @@ pipe( `takeLast` will take only the last n emissions from the source. -```reason -Wonka.fromArray([|1, 2, 3, 4, 5, 6|]); - |> Wonka.takeLast(3) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 4 5 6 to the console. */ -``` - ```typescript import { fromArray, pipe, takeLast, subscribe } from 'wonka'; pipe( fromArray([1, 2, 3, 4, 5, 6]), takeLast(3), - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); // Prints 4 5 6 to the console. @@ -756,18 +498,6 @@ pipe( Take emissions from an outer source until an inner source (notifier) emits. -```reason -let source = Wonka.interval(100); -let notifier = Wonka.interval(500); - -source - |> Wonka.takeUntil(notifier) - |> Wonka.subscribe((. x) => print_int(x)); - -/* Pauses 100ms, prints 0, pauses 100ms, prints 1, pauses 100ms, prints 2, pauses 100ms, -prints 3, pauses 100, then completes (notifier emits). */ -``` - ```typescript import { interval, pipe, takeUntil, subscribe } from 'wonka'; @@ -777,7 +507,7 @@ const notifier = interval(500); pipe( source, takeUntil(notifier), - subscribe(val => console.log(val)) + subscribe((val) => console.log(val)) ); // Pauses 100ms, prints 0, pauses 100ms, prints 1, pauses 100ms, prints 2, pauses 100ms, @@ -788,16 +518,6 @@ pipe( Take emissions from the stream while they return `true` for the provided predicate function. If the first emission does not return `true`, no values will be `Push`ed to the sink. -```reason -let source = Wonka.fromArray([|1, 2, 3, 4, 5, 6|]); - -source - |> Wonka.takeWhile((. x) => x < 5) - |> Wonka.subscribe((. x) => print_int(x)); - -/* Prints 1 2 3 4 to the console. */ -``` - ```typescript import { pipe, fromArray, takeWhile, subscribe } from 'wonka'; @@ -805,8 +525,8 @@ const source = fromArray([1, 2, 3, 4, 5, 6]); pipe( source, - takeWhile(val => val < 5), - subscribe(val => console.log(val)) + takeWhile((val) => val < 5), + subscribe((val) => console.log(val)) ); // Prints 1 2 3 4 to the console. @@ -821,17 +541,6 @@ receives and skips values while the silence is still ongoing. This is very similar to `debounce` but instead of waiting for leading time before a value it waits for trailing time after a value. -> _Note:_ This operator is only available in JavaScript environments, and will be excluded -> when compiling natively. - -```reason -Wonka.interval(10) - |> Wonka.throttle((. _x) => 50) - |> Wonka.take(2) - |> Wonka.subscribe((. x) => print_int(x)); -/* Outputs 0 6 to the console. */ -``` - ```typescript import { pipe, interval, throttle, take, subscribe } from 'wonka'; diff --git a/docs/api/sinks.md b/docs/api/sinks.md index 857b8fa..0df231e 100644 --- a/docs/api/sinks.md +++ b/docs/api/sinks.md @@ -9,12 +9,6 @@ A sink in Wonka expects to be delivered data. A `sink` communicates with a sourc `subscribe` accepts a callback function to execute when data is received from the source, in addition to the source itself. -```reason -Wonka.fromArray([|1, 2, 3|]) - |> Wonka.subscribe((. x) => print_int(x)); -/* Prints 123 to the console. */ -``` - ```typescript import { pipe, fromArray, subscribe } from 'wonka'; @@ -28,13 +22,6 @@ pipe( unsubscribe from the source. This allows you to cancel a source and stop receiving new incoming values. -```reason -let subscription = source - |> Wonka.subscribe((. x) => print_int(x)); - -subscription.unsubscribe(); -``` - ```typescript import { pipe, subscribe } from 'wonka'; @@ -51,12 +38,6 @@ unsubscribe(); `forEach` works the same as `subscribe` but doesn't return a subscription. It will just call the passed callback for each incoming value. -```reason -Wonka.fromArray([|1, 2, 3|]) - |> Wonka.forEach((. x) => print_int(x)); -/* Returns unit; Prints 123 to the console. */ -``` - ```typescript import { pipe, fromArray, forEach } from 'wonka'; @@ -75,13 +56,6 @@ used as part of the stream itself. In this example we're using [`onPush`](./operators.md#onpush) to pass a callback to react to incoming values instead. -```reason -Wonka.fromArray([|1, 2, 3|]) - |> Wonka.onPush((. x) => print_int(x)) - |> Wonka.publish; -/* Prints 123 to the console. */ -``` - ```typescript import { pipe, fromArray, onPush, publish } from 'wonka'; @@ -104,19 +78,12 @@ before it returns an array. > _Note:_ If you're using this sink, make sure that your input source streams > the values you're collecting partly or fully synchronously. -```reason -Wonka.fromArray([|1, 2, 3|]) - |> Wonka.map((. x) => x * 2) - |> Wonka.toArray -/* Returns [|2, 4, 6|] */ -``` - ```typescript import { pipe, fromArray, map, toArray } from 'wonka'; pipe( fromArray([1, 2, 3]), - map(x => x * 2), + map((x) => x * 2), toArray ); // Returns [2, 4, 6] ``` @@ -125,28 +92,12 @@ pipe( `toPromise` returns a promise, which resolves on the last value of a source. -> _Note:_ This source is only available in JavaScript environments, and will be excluded -> when compiling natively. - -```reason -Wonka.fromArray([|1, 2, 3|]) - |> Wonka.toPromise - |> Js.Promise.then_(x => { - print_int(x); - Js.Promise.resolve(()) - }) -/* Prints 3 to the console. */ -``` - ```typescript import { pipe, fromArray, toPromise } from 'wonka'; -const promise = pipe( - fromArray([1, 2, 3]), - toPromise, -); +const promise = pipe(fromArray([1, 2, 3]), toPromise); -promise.then(x => console.log(x)); +promise.then((x) => console.log(x)); // Prints 3 to the console. ``` @@ -160,31 +111,13 @@ values as a source. As per the specification, the Observable is annotated using `Symbol.observable`. -> _Note:_ This sink is only available in JavaScript environments, and will be excluded -> when compiling natively. - -```reason -let observable = Wonka.fromArray([|1, 2, 3|]) - |> Wonka.toObservable; - -observable##subscribe([@bs] { - as _; - pub next = value => print_int(value); - pub complete = () => (); - pub error = _ => (); -}); /* Prints 1 2 3 to the console. */ -``` - ```typescript import { pipe, fromArray, toObservable } from 'wonka'; -const observable = pipe( - fromArray([1, 2, 3]), - toObservable, -); +const observable = pipe(fromArray([1, 2, 3]), toObservable); observable.subscribe({ - next: value => console.log(value), + next: (value) => console.log(value), complete: () => {}, error: () => {}, }); // Prints 1 2 3 to the console. @@ -199,33 +132,14 @@ Since Wonka's sources are very similar to callbags and only diverge from the spe minimally, Callbags map to Wonka's sources very closely and `toCallbag` only creates a thin wrapper which is mostly concerned with converting between the type signatures. -> _Note:_ This sink is only available in JavaScript environments, and will be excluded -> when compiling natively. - -```reason -/* This example uses the callbag-iterate package for illustrative purposes */ -[@bs.module] external callbagIterate: - (. ('a => unit)) => (. Wonka.callbagT('a)) => unit = "callbag-iterate"; - -let callbag = Wonka.fromArray([|1, 2, 3|]) - |> Wonka.toCallbag; - -callbagIterate(. value => { - print_int(value); -})(. callbag); /* Prints 1 2 3 to the console. */ -``` - ```typescript import { pipe, fromArray, toCallbag } from 'wonka'; // This example uses the callbag-iterate package for illustrative purposes import callbagIterate from 'callbag-iterate'; -const callbag = pipe( - fromArray([1, 2, 3]), - toCallbag, -); +const callbag = pipe(fromArray([1, 2, 3]), toCallbag); -callbagIterate(value => console.log(value))(callbag); +callbagIterate((value) => console.log(value))(callbag); // Prints 1 2 3 to the console. ``` diff --git a/docs/api/sources.md b/docs/api/sources.md index b91aec8..a6a78ae 100644 --- a/docs/api/sources.md +++ b/docs/api/sources.md @@ -9,35 +9,19 @@ A "source" in Wonka is a provider of data. It provides data to a "sink" when the `fromArray` transforms an array into a source, emitting each item synchronously. -```reason -Wonka.fromArray([|1, 2, 3|]); -``` - ```typescript import { fromArray } from 'wonka'; fromArray([1, 2, 3]); ``` -## fromList - -`fromList` transforms a list into a source, emitting each item synchronously. - -> _Note:_ This operator is only useful in Reason / OCaml where lists are a builtin -> data structure. - -This is otherwise functionally the same as `fromArray`. - -```reason -Wonka.fromList([1, 2, 3]); -``` - ## fromValue `fromValue` takes a single value and creates a source that emits the value and completes immediately afterwards. -```reason -Wonka.fromValue("a value"); +```typescript +import { fromValue } from 'wonka'; +fromValue(1); ``` ## make @@ -60,35 +44,16 @@ is being cancelled, since the sink unsubscribed. In this example we create a source that waits for a promise to resolve and emits values from the array of that promise. -```reason -let waitForArray = () => Js.Promise.resolve([|1, 2, 3|]); - -let source = Wonka.make((. observer) => { - let (next, complete) = observer; - let cancelled = ref(false); - let promise = waitForArray(); - - Js.Promise.then_(arr => { - if (!cancelled^) { - Array.iter(next, arr); - complete(); - } - }, promise); - - () => cancelled := true; -}); -``` - ```typescript import { make } from 'wonka'; const waitForArray = () => Promise.resolve([1, 2, 3]); -const source = make(observer => { +const source = make((observer) => { const { next, complete } = observer; let cancelled = false; - waitForArray().then(arr => { + waitForArray().then((arr) => { if (!cancelled) { arr.forEach(next); complete(); @@ -111,18 +76,8 @@ A subject can be very useful as a full event emitter. It allows you to pass a so around but also have access to the observer functions to emit events away from the source itself. -```reason -let subject = Wonka.makeSubject(); -let { source, next, complete } = subject; - -/* This will push the values synchronously to any subscribers of source */ -next(1); -next(2); -next(complete); -``` - ```typescript -import { makeSubject } from 'wonka' +import { makeSubject } from 'wonka'; const subject = makeSubject(); const { source, next, complete } = subject; @@ -137,19 +92,6 @@ next(complete); `fromDomEvent` will turn a DOM event into a Wonka source, emitting the DOM events on the source whenever the DOM emits them on the passed element. -> _Note:_ This source is only available in JavaScript environments, and will be excluded -> when compiling natively. - -```reason -open Webapi.Dom; -open Document; - -let element = getElementById("root", document)->Belt.Option.getExn; - -Wonka.fromDomEvent(element, "click") - |> Wonka.subscribe((. click) => Js.log(click)); -``` - ```typescript import { pipe, fromDomEvent, subscribe } from 'wonka'; @@ -157,7 +99,7 @@ const element = document.getElementById('root'); pipe( fromDomEvent(element, 'click'), - subscribe(e => console.log(e)) + subscribe((e) => console.log(e)) ); ``` @@ -166,17 +108,6 @@ pipe( `fromPromise` transforms a promise into a source, emitting the promisified value on the source once it resolves. -> _Note:_ This source is only available in JavaScript environments, and will be excluded -> when compiling natively. - -```reason -let promise = Js.Promise.make(1); /* Just an example promise */ - -Wonka.fromPromise(promise) - |> Wonka.subscribe((. x) => Js.log(x)); -/* Prints 1 to the console. */ -``` - ```typescript import { pipe, fromPromise, subscribe } from 'wonka'; @@ -184,7 +115,7 @@ const promise = Promise.resolve(1); // Just an example promise pipe( fromPromise(promise), - subscribe(e => console.log(e)) + subscribe((e) => console.log(e)) ); // Prints 1 to the console. ``` @@ -194,9 +125,6 @@ pipe( The resulting source will behave exactly the same as the Observable that it was passed, so it will start, end, and push values identically. -> _Note:_ This source is only available in JavaScript environments, and will be excluded -> when compiling natively. - ```typescript import { pipe, fromObservable, subscribe } from 'wonka'; @@ -207,34 +135,10 @@ const observable = Observable.from([1, 2, 3]); pipe( fromObservable(observable), - subscribe(e => console.log(e)) + subscribe((e) => console.log(e)) ); // Prints 1 2 3 to the console ``` -If you're using Reason in a JavaScript environment and you're interested in this -operator, you may be using a library to create or get Observables. - -Some libraries don't expose Observables with the same BuckleScript type signature -that Wonka uses to type them. So while Wonka's `observableT` type is fairly -lenient it may not work for you. - -```reason -type observableT('a) = {. - [@bs.meth] "subscribe": observerT('a) => subscriptionT -}; -``` - -To work around this you can create a function that casts your observable type -to Wonka's `observableT`. - -```reason -type yourObservableType('a); -external asObservable: yourObservableType('a) => Wonka.observableT('a) = "%identity"; -``` - -This snippet would create an `asObservable` function, which can type-cast your -Observable type to `Wonka.observableT` and compiles away completely. - ## fromCallbag `fromCallbag` transforms a [spec-compliant JS Callbag](https://github.com/callbag/callbag) into a source. @@ -243,21 +147,6 @@ Since Wonka's sources are very similar to callbags and only diverge from the spe minimally, Callbags map to Wonka's sources very closely and the `fromCallbag` wrapper is very thin and mostly concerned with converting between the type signatures. -> _Note:_ This source is only available in JavaScript environments, and will be excluded -> when compiling natively. - -```reason -/* This example uses the callbag-from-iter package for illustrative purposes */ -[@bs.module] external callbagFromArray: - array('a) => Wonka.callbagT('a) = "callbag-from-iter"; - -let callbag = callbagFromArray([|1, 2, 3|]); - -Wonka.fromCallbag(callbag) - |> Wonka.subscribe((. x) => Js.log(x)); -/* Prints 1 2 3 to the console. */ -``` - ```typescript import { pipe, fromCallbag, subscribe } from 'wonka'; @@ -268,7 +157,7 @@ const callbag = callbagFromArray([1, 2, 3]); pipe( fromCallbag(callbag), - subscribe(e => console.log(e)) + subscribe((e) => console.log(e)) ); // Prints 1 2 3 to the console. ``` @@ -277,22 +166,12 @@ pipe( `interval` creates a source that emits values after the given amount of milliseconds. Internally it uses `setInterval` to accomplish this. -> _Note:_ This source is only available in JavaScript environments, and will be excluded -> when compiling natively. - -```reason -Wonka.interval(50) - |> Wonka.subscribe((. x) => Js.log(x)); -/* Prints 0 1 2... to the console. */ -/* The incrementing number is logged every 50ms */ -``` - ```typescript import { pipe, interval, subscribe } from 'wonka'; pipe( interval(50), - subscribe(e => console.log(e)) + subscribe((e) => console.log(e)) ); // Prints 0 1 2... to the console. // The incrementing number is logged every 50ms ``` @@ -302,20 +181,12 @@ pipe( This is a source that doesn't emit any values when subscribed to and immediately completes. -```reason -Wonka.empty - |> Wonka.forEach((. value) => { - /* This will never be called */ - () - }); -``` - ```typescript import { pipe, empty, forEach } from 'wonka'; pipe( empty, - forEach(value => { + forEach((value) => { /* This will never be called */ }) ); @@ -326,20 +197,12 @@ pipe( This is source is similar to [`empty`](#empty). It doesn't emit any values but also never completes. -```reason -Wonka.never - |> Wonka.forEach((. value) => { - /* This will never be called */ - () - }); -``` - ```typescript import { pipe, never, forEach } from 'wonka'; pipe( never, - forEach(value => { + forEach((value) => { /* This will never be called */ }) ); diff --git a/docs/basics/architecture.md b/docs/basics/architecture.md index 1fe2f46..7af8c7c 100644 --- a/docs/basics/architecture.md +++ b/docs/basics/architecture.md @@ -22,26 +22,27 @@ This is called a "push" signal. Because a sink has a start, incoming values, and an end, there are three signals that a sink can receive: `Start`, `Push`, and `End`. -``` reason -type signalT('a) = - | Start - | Push('a) - | End; +```typescript +type Start = { tag: 0 }; // & [TalkbackFn] +type Push = { tag: 1 } & [T]; +type End = 0; -type sinkT('a) = (. signalT('a)) => unit; +type Signal = Start | Push | End; + +type Sink = (signal: Signal) => void; ``` As shown, the sink is just a function accepting a signal as its argument. When the stream starts then the sink is called with `Start`, -Then for every incoming, new value it's called with `Push('a)`, +Then for every incoming, new value it's called with `Push`, and when the stream ends it's finally called with `End`. Since we want a source to send these values to the sink, the source is also just a function and it accepts a sink as its argument. -``` reason -type sourceT('a) = sinkT('a) => unit; +```typescript +type Source = (sink: Sink) => void; ``` This is completely sufficient to represent simple "push" streams, where @@ -55,10 +56,10 @@ sink that their source will be called with. The type signature of an operator with no other arguments is thus: -``` reason -type operatorT('a, 'b) = sourceT('a) => sourceT('b); +```typescript +type Operator = (source: Source) => Source; /* which is the same as: */ -type operatorT('a, 'b) = (sourceT('a), sinkT('b)) => unit; +type Operator = (source: Source) => (sink: Sink) => void; ``` ## Adding Callbacks @@ -76,18 +77,17 @@ We can achieve this by passing a callback function on when a stream starts. In Wonka, a sink's `Start` signal also carries a callback that is used to communicate back to the source, making these "talkback signals" flow from the bottom to the top. -``` reason -type talkbackT = - | Pull - | Close; +```typescript +const enum TalkbackKind { + Pull = 0, + Close = 1, +} -type signalT('a) = - | Start((. talkbackT) => unit) - | Push('a) - | End; +type TalkbackFn = (signal: TalkbackKind) => void; +type Start = { tag: 0 } & [TalkbackFn]; ``` -This is like the previous `signalT('a)` definition, but the `Start` signal has the +This is like the previous `Signal` definition, but the `Start` signal has the callback definition now. The callback accepts one of two signals: `Pull` or `Close`. `Close` is a signal that will cancel the stream. It tells the source to stop sending @@ -117,12 +117,12 @@ like an event dispatcher. In Wonka there's a separate type for subjects however, since this reduces the complexity of its streams a lot: -``` reason -type subjectT('a) = { - source: sourceT('a), - next: 'a => unit, - complete: unit => unit, -}; +```reason +interface Subject { + next(value: T): void; + complete(): void; + source: Source; +} ``` Hence in Wonka a subject is simply a wrapper around a source and a `next` and `complete` diff --git a/docs/index.md b/docs/index.md index 7e77b02..d7dcc97 100644 --- a/docs/index.md +++ b/docs/index.md @@ -21,23 +21,14 @@ synchronously if an iterable source runs synchronously. It also comes with many operators that users from [RxJS](https://github.com/ReactiveX/rxjs) will be used to. -## Compatibility +## Reason Support -Wonka is written in [Reason](https://reasonml.github.io/), a dialect of OCaml, and can hence be used -for native applications. It is also compiled using [BuckleScript](https://bucklescript.github.io) to plain -JavaScript and has typings for [TypeScript](https://www.typescriptlang.org/) and [Flow](https://flow.org/). +Wonka used to be written in [Reason](https://reasonml.github.io/),, a dialect of OCaml, and was usable +for native development and compileable with [BuckleScript](https://bucklescript.github.io). +Out of the box it supported usage with BuckleScript, `bs-native`, Dune, and Esy. -This means that out of the box Wonka is usable in any project that use the following: - -- Plain JavaScript -- TypeScript -- Flow -- Reason/OCaml with BuckleScript -- Reason/OCaml with `bs-native` -- Reason/OCaml with Dune and Esy - -In summary, Wonka provides a consistent interface in and works across -TypeScript/Flow/Reason/OCaml environments with full type safety. +If you're looking for the legacy version that supported this, you may want to install v4 or v5 rather +than v6 onwards, which converted the project to TypeScript. ## About the docs diff --git a/docs/migration.md b/docs/migration.md index 7cf0db8..e679b14 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -6,6 +6,23 @@ order: 2 This page lists breaking changes and migration guides for various major releases of Wonka. +## v6.0.0 + +In `v6.0.0` of Wonka, we've migrated fully to TypeScript. +If you're using this project with Reason or OCaml before, we're sorry for +the inconvenience. However, v4 and v5-rc will remain usable for these +platforms and languages. + +The internal API and data structures of Wonka haven't changed in `v6.0.0` +compared to the prior releases and are based on `v4.0.14`. This means that +from a TypeScript, Flow, and JS perspective, `v6.0.0` is backwards compatible +and continues to function as before. + +However, the `fromList` API has been removed so far, and we reserve ourselves +room to make more breaking changes were behaviour before was broken. + +We're also dropping IE11 support and are now bundling against an ES2015 target. + ## v4.0.0 In `v4.0.0` of Wonka, we've migrated to BuckleScript v7 and diff --git a/gatsby/theme.css b/gatsby/theme.css deleted file mode 100644 index 3a37247..0000000 --- a/gatsby/theme.css +++ /dev/null @@ -1,30 +0,0 @@ -@font-face { - font-family: 'phantom-sans'; - src: url("https://phantomsans.kitten.sh/PhantomSans05VAR.woff2") format("woff2-variations"), - url("https://phantomsans.kitten.sh/PhantomSans05VAR.ttf") format("truetype-variations"), - url("https://phantomsans.kitten.sh/PhantomSans-Regular.woff2") format("woff2"), - url("https://phantomsans.kitten.sh/PhantomSans-Regular.ttf") format("truetype"); - font-weight: 1 999; - font-display: swap; - font-style: normal; -} - -@font-face { - font-family: 'space-mono'; - font-style: italic; - font-weight: 400; - font-display: swap; - src: local('Space Mono Italic'), - local('SpaceMono-Italic'), - url(https://fonts.gstatic.com/s/spacemono/v4/i7dNIFZifjKcF5UAWdDRYERMR3K_MQacbw.woff2) format('woff2'); -} - -@font-face { - font-family: 'space-mono'; - font-style: normal; - font-weight: 400; - font-display: swap; - src: local('Space Mono'), - local('SpaceMono-Regular'), - url(https://fonts.gstatic.com/s/spacemono/v4/i7dPIFZifjKcF5UAWdDRYEF8RXi4EwQ.woff2) format('woff2'); -} diff --git a/gatsby/theme.js b/gatsby/theme.js deleted file mode 100644 index 1fa8db6..0000000 --- a/gatsby/theme.js +++ /dev/null @@ -1,50 +0,0 @@ -import nightOwlLight from 'prism-react-renderer/themes/nightOwlLight'; -import './theme.css'; - -const systemFonts = [ - '-apple-system', - 'BlinkMacSystemFont', - 'Segoe UI', - 'Roboto', - 'Helvetica Neue', - 'Arial', - 'Noto Sans', - 'sans-serif', - 'Apple Color Emoji', - 'Segoe UI Emoji', - 'Segoe UI Symbol', - 'Noto Color Emoji', -]; - -export const fonts = { - header: ['phantom-sans', ...systemFonts], - code: ['space-mono', 'monospace'], - body: systemFonts, -}; - -export const colors = { - bg: '#ffffff', - bgPassive: '#f0f0f2', - bgActive: '#fcfafe', - fg: '#36313d', - fgHeading: '#000000', - fgPassive: '#78757a', - fgActive: '#f5735f', -}; - -export const prismTheme = nightOwlLight; -export const fontSizes = [12, 14, 16, 20, 24, 32, 48, 64, 96]; -export const fontWeights = ['300', '400', '500', '700', '800']; -export const letterSpacings = ['normal', '0.01em', '0.05em', '0.1em']; -export const borderWidths = ['1px', '0.1rem', '0.25rem']; -export const space = [0, 4, 8, 16, 32, 64]; -export const sizes = [0, 64, 260, 430, 540, 650, 870, 980, 1400]; -export const breakpoints = ['55em', '70em']; -export const radii = [4, 8, 16]; -export const zIndices = [0, 1, 2, 3]; - -export const borders = [ - `${borderWidths[0]} solid ${colors.bgPassive}`, - `${borderWidths[1]} solid ${colors.bgPassive}`, - `${borderWidths[2]} solid ${colors.bgPassive}`, -]; diff --git a/gatsby/typography.js b/gatsby/typography.js deleted file mode 100644 index 3b4da25..0000000 --- a/gatsby/typography.js +++ /dev/null @@ -1,15 +0,0 @@ -import Typography from 'typography'; -import * as theme from './theme'; - -const typography = new Typography({ - includeNormalize: false, - baseFontSize: '18px', - baseLineHeight: 1.5, - scaleRatio: 46 / 18, - headerFontFamily: theme.fonts.header, - headerWeight: '500', - bodyFontFamily: theme.fonts.body, - bodyWeight: '400', -}); - -export default typography; -- knotmirror 0.0.1