Mirror: 🎩 A tiny but capable push & pull stream library for TypeScript and Flow
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add misc pages to documentation (#30)

* Add introduction content

* Add "Getting Started" page

* Add initial basics section

* Add index content for Basics

* Fix comment syntax in architecture

* Add publish and forEach to sinks doc

* Add toPromise to sinks doc

* Add fromPromise to sources doc

* Apply suggestions and rewrite some sections

Co-authored-by: Parker Ziegler <parkerziegler@users.noreply.github.com>

authored by

Phil Plückthun
Parker Ziegler
and committed by
GitHub
9daef0ac d5bd69aa

+504 -15
+1 -1
docs/api/index.md
··· 1 1 --- 2 2 title: API Reference 3 - order: 1 3 + order: 3 4 4 --- 5 5 6 6 Wonka, in essence, can be used to create sources, to transform sources with operators,
+103 -12
docs/api/sinks.md
··· 10 10 `subscribe` accepts a callback function to execute when data is received from the source, in addition to the source itself. 11 11 12 12 ```reason 13 - open Wonka; 14 - open Wonka_sources; 15 - open Wonka_sinks; 16 - 17 - let source = fromArray([|1, 2, 3|]); 18 - source |> subscribe((. _val) => print_int(_val)); 13 + Wonka.fromArray([|1, 2, 3|]) 14 + |> Wonka.subscribe((. x) => print_int(x)); 19 15 /* Prints 123 to the console. */ 20 16 ``` 21 17 22 18 ```typescript 23 19 import { pipe, fromArray, subscribe } from 'wonka'; 24 20 25 - const source = fromArray([1, 2, 3]); 21 + pipe( 22 + fromArray([1, 2, 3]), 23 + subscribe((x) => console.log(x)) 24 + ); // Prints 123 to the console. 25 + ``` 26 + 27 + `subscribe` also returns a "subscription" type, which can be used to 28 + unsubscribe from the source. This allows you to cancel a source and stop receiving 29 + new incoming values. 30 + 31 + ```reason 32 + let subscription = source 33 + |> Wonka.subscribe((. x) => print_int(x)); 34 + 35 + subscription.unsubscribe(); 36 + ``` 37 + 38 + ```typescript 39 + import { pipe, subscribe } from 'wonka'; 40 + 41 + const [unsubscribe] = pipe( 42 + source, 43 + subscribe((x) => console.log(x)); 44 + ); 45 + 46 + unsubscribe(); 47 + ``` 48 + 49 + ## forEach 50 + 51 + `forEach` works the same as `subscribe` but doesn't return a subscription. 52 + It will just call the passed callback for each incoming value. 53 + 54 + ```reason 55 + Wonka.fromArray([|1, 2, 3|]) 56 + |> Wonka.forEach((. x) => print_int(x)); 57 + /* Returns unit; Prints 123 to the console. */ 58 + ``` 59 + 60 + ```typescript 61 + import { pipe, fromArray, forEach } from 'wonka'; 62 + 63 + pipe( 64 + fromArray([1, 2, 3]), 65 + forEach((x) => console.log(x)) 66 + ); // Returns undefined; Prints 123 to the console. 67 + ``` 68 + 69 + ## publish 70 + 71 + `publish` subscribes to a source, like `subscribe` does, but doesn't accept 72 + a callback function. It's useful for side-effects, where the values are already being 73 + used as part of the stream itself. 74 + 75 + In this example we're using [`onPush`](./operators.md#onpush) to pass a callback to react to incoming 76 + values instead. 77 + 78 + ```reason 79 + Wonka.fromArray([|1, 2, 3|]) 80 + |> Wonka.onPush((. x) => print_int(x)) 81 + |> Wonka.publish; 82 + /* Prints 123 to the console. */ 83 + ``` 84 + 85 + ```typescript 86 + import { pipe, fromArray, onPush, publish } from 'wonka'; 26 87 27 88 pipe( 28 - source, 29 - subscribe((x) => { 30 - console.log(x); 31 - }); 89 + fromArray([1, 2, 3]), 90 + onPush((x) => console.log(x)), 91 + publish 92 + ); // Prints 123 to the console. 93 + ``` 94 + 95 + ## toPromise 96 + 97 + `toPromise` returns a promise, which resolves on the last value of a source. 98 + 99 + > _Note:_ This source is only available in JavaScript environments, and will be excluded 100 + > when compiling natively. 101 + 102 + ```reason 103 + Wonka.fromArray([|1, 2, 3|]) 104 + |> Wonka.toPromise 105 + |> Js.Promise.then_(x => { 106 + print_int(x); 107 + Js.Promise.resolve(()) 108 + }) 109 + /* Prints 3 to the console. */ 110 + ``` 111 + 112 + ```typescript 113 + import { pipe, fromArray, toPromise } from 'wonka'; 114 + 115 + const promise = pipe( 116 + fromArray([1, 2, 3]), 117 + toPromise, 32 118 ); 33 - // Prints 123 to the console. 119 + 120 + promise.then(x => console.log(x)); 121 + // Prints 3 to the console. 34 122 ``` 123 + 124 + If you have a source that doesn't complete and are looking to resolve on the first 125 + value instead of the last, you may have to apply `take(1)` to your source.
+28 -1
docs/api/sources.md
··· 137 137 `fromDomEvent` will turn a DOM event into a Wonka source, emitting the DOM events 138 138 on the source whenever the DOM emits them on the passed element. 139 139 140 - > This source will only work in a JavaScript environment, and will be excluded 140 + > _Note:_ This source is only available in JavaScript environments, and will be excluded 141 141 > when compiling natively. 142 142 143 143 ```reason ··· 159 159 fromDomEvent(element, 'click'), 160 160 subscribe(e => console.log(e)) 161 161 ); 162 + ``` 163 + 164 + ## fromPromise 165 + 166 + `fromPromise` transforms a promise into a source, emitting the promisified value on 167 + the source once it resolves. 168 + 169 + > _Note:_ This source is only available in JavaScript environments, and will be excluded 170 + > when compiling natively. 171 + 172 + ```reason 173 + let promise = Js.Promise.make(1); /* Just an example promise */ 174 + 175 + Wonka.fromPromise(promise) 176 + |> Wonka.subscribe((. x) => Js.log(x)); 177 + /* Prints 1 to the console. */ 178 + ``` 179 + 180 + ```typescript 181 + import { pipe, fromPromise, subscribe } from 'wonka'; 182 + 183 + const promise = Promise.resolve(1); // Just an example promise 184 + 185 + pipe( 186 + fromPromise(promise), 187 + subscribe(e => console.log(e)) 188 + ); // Prints 1 to the console. 162 189 ``` 163 190 164 191 ## empty
+129
docs/basics/architecture.md
··· 1 + --- 2 + title: Architecture 3 + order: 1 4 + --- 5 + 6 + It may be useful to understand how Wonka's sources work internally 7 + if you want to write a new operator from scratch or contribute to it. 8 + 9 + This section explains how Wonka works internally and how it differs from 10 + the callbag specification. 11 + 12 + ## Just Functions 13 + 14 + Internally Wonka only uses functions with rather simple signatures to 15 + make its streams work. 16 + 17 + We have sinks on one end, which need to receive values, and sources 18 + on the other, which need to send values. 19 + The sink is therefore just a function that we call with values over time. 20 + This is called a "push" signal. 21 + 22 + Because a sink has a start, incoming values, and an end, there are three 23 + signals that a sink can receive: `Start`, `Push`, and `End`. 24 + 25 + ``` reason 26 + type signalT('a) = 27 + | Start 28 + | Push('a) 29 + | End; 30 + 31 + type sinkT('a) = (. signalT('a)) => unit; 32 + ``` 33 + 34 + As shown, the sink is just a function accepting a signal as its argument. 35 + 36 + When the stream starts then the sink is called with `Start`, 37 + Then for every incoming, new value it's called with `Push('a)`, 38 + and when the stream ends it's finally called with `End`. 39 + 40 + Since we want a source to send these values to the sink, the source is 41 + also just a function and it accepts a sink as its argument. 42 + 43 + ``` reason 44 + type sourceT('a) = sinkT('a) => unit; 45 + ``` 46 + 47 + This is completely sufficient to represent simple "push" streams, where 48 + values are pushed from the source to the sink. They essentially flow from 49 + the "top" to the "bottom". 50 + 51 + Operators are just functions that transform a source. They take a 52 + source and some number of arguments and return a new source. 53 + Internally they may also create a new sink function that wraps the 54 + sink that their source will be called with. 55 + 56 + The type signature of an operator with no other arguments is thus: 57 + 58 + ``` reason 59 + type operatorT('a, 'b) = sourceT('a) => sourceT('b); 60 + /* which is the same as: */ 61 + type operatorT('a, 'b) = (sourceT('a), sinkT('b)) => unit; 62 + ``` 63 + 64 + ## Adding Callbacks 65 + 66 + To complete this pattern we're still missing a single piece: callbacks! 67 + 68 + Previously, we've looked at how sources are functions that accept sinks, which 69 + in turn are functions accepting a signal. What we're now missing is what makes 70 + Wonka's streams also work as iterables. 71 + 72 + We'd also like to be able to _cancel_ streams, so that we can interrupt 73 + them and not receive any more values. 74 + 75 + We can achieve this by passing a callback function on when a stream starts. 76 + In Wonka, a sink's `Start` signal also carries a callback that is used to communicate 77 + back to the source, making these "talkback signals" flow from the bottom to the top. 78 + 79 + ``` reason 80 + type talkbackT = 81 + | Pull 82 + | Close; 83 + 84 + type signalT('a) = 85 + | Start((. talkbackT) => unit) 86 + | Push('a) 87 + | End; 88 + ``` 89 + 90 + This is like the previous `signalT('a)` definition, but the `Start` signal has the 91 + callback definition now. The callback accepts one of two signals: `Pull` or `Close`. 92 + 93 + `Close` is a signal that will cancel the stream. It tells the source to stop sending 94 + new values. 95 + 96 + The `Pull` signal is a signal that asks the source to send the next value. This is 97 + especially useful to represent iterables. In practice a user would never send this 98 + signal explicitly, but sinks would send the signal automatically after receiving the 99 + previous value from the stream. 100 + 101 + In asynchronous streams the `Pull` signal is of course a no-op. It won't do 102 + anything since we can't ask for asynchronous values. 103 + 104 + ## Comparison to Callbags 105 + 106 + This is the full pattern of Wonka's streams and it's a little different from callbags. 107 + These changes have been made to make Wonka's streams typesafe. But there's 108 + also a small omission that makes Wonka's streams easier to explain. 109 + 110 + In Callbags, sources don't just accept sinks as their only argument. In fact, in 111 + callbags the source would also receive three different signals. This can be useful 112 + to represent "subjects". 113 + 114 + A subject is a sink and source combined. It can be used to dispatch values imperatively, 115 + like an event dispatcher. 116 + 117 + In Wonka there's a separate type for subjects however, since this reduces the 118 + complexity of its streams a lot: 119 + 120 + ``` reason 121 + type subjectT('a) = { 122 + source: sourceT('a), 123 + next: 'a => unit, 124 + complete: unit => unit, 125 + }; 126 + ``` 127 + 128 + Hence in Wonka a subject is simply a wrapper around a source and a `next` and `complete` 129 + method.
+66
docs/basics/background.md
··· 1 + --- 2 + title: Background 3 + order: 0 4 + --- 5 + 6 + In a lot of daily tasks in programming we come across patterns where 7 + we deal with lists of values. In JavaScript we'd reach to arrays to 8 + collect them, and luckily there are plenty of methods built-in 9 + to modify such an array, such as `map`, `filter` and `reduce`. 10 + 11 + Things become more complex when we're dealing with lists that 12 + are infinite. In such a case we may reach to iterables. We could 13 + expect an iterable that continuously outputs numbers, counting up 14 + infinitely, or rather until it reaches the maximum integer. 15 + 16 + When we're dealing with asynchronous lists of values things also 17 + become more complex. We're often confronted with event streams, 18 + where events or even regular values come in over time. 19 + 20 + In either case what we're dealing with are essentially [immutable, 21 + asynchronous iterables](https://medium.com/@andrestaltz/2-minute-introduction-to-rx-24c8ca793877). 22 + 23 + Wonka is a library to provide a primitive to solve these problems and 24 + is both an iterable programming library _and_ a reactive stream programming 25 + library. 26 + 27 + It can be compared to observables and iterables in one library, but is 28 + based on and essentially a ["callbag" library](https://staltz.com/why-we-need-callbags.html). 29 + 30 + ## Sources, Operators, and Sinks 31 + 32 + When we're thinking of solving problems with streams, it's always 33 + a good idea to look at how we're solving problems with arrays. 34 + 35 + Since Wonka's streams are an entirely new primitive, Wonka has to provide 36 + all utilities that you as a developer may need to work with them. 37 + Specifically we have to make sure that it's easy to _create_, _transform_, 38 + and _consume_ these streams. 39 + 40 + If we compare these utilities to arrays, _creating_ an array is similar to 41 + creating a stream. So Wonka has utilities such as [`fromArray`](../api/sources.md#fromArray) to 42 + create a new source. 43 + 44 + A **source** is what we call a stream in Wonka. This is because it 45 + doesn't strictly follow the definition or specification of observables nor 46 + iterables. So we're calling them **sources** since they're just a **source** 47 + of values over time. 48 + 49 + Next we would like to _transform_ sources to make them useful. 50 + Like with arrays we may want to map, filter, and reduce them, 51 + so Wonka has **operators** like [`filter`](../api/operators.md#filter) and [`map`](../api/operators.md#map). 52 + But since Wonka is like a toolkit, it comes with a lot more utilities than 53 + just that. 54 + 55 + In general, **operators** will accept some arguments and a source 56 + and output a new, transformed source. 57 + 58 + Lastly, the sources we create wouldn't be of much use if we weren't 59 + able to _consume_ them. This is similar to using `forEach` on an 60 + array to iterate over its values. Wonka has a [`subscribe`](../api/sinks.md#subscribe) function which 61 + works similarly to how an observable's subscribe method may work. 62 + This is because Wonka's sources are entirely cancellable. 63 + 64 + To summarise, Wonka's streams are _sources_ of values, which 65 + can be transformed using _operators_, which create new _sources_. 66 + If we want to consume a _source_ we use a _sink_.
+12
docs/basics/index.md
··· 1 + --- 2 + title: Basics 3 + order: 2 4 + --- 5 + 6 + Wonka introduces a new primitive for streams. 7 + This part of the documentation explains both the motivation 8 + behind creating and using a new stream primitive and how these 9 + work internally in Wonka. 10 + 11 + - [Background](./background.md) — learn what streams are 12 + - [Architecture](./architecture.md) — learn how Wonka's streams work internally
+119
docs/getting-started.md
··· 1 + --- 2 + title: Getting Started 3 + order: 1 4 + --- 5 + 6 + This page will explain how to install the Wonka package and 7 + its basic usage and helper functions. 8 + 9 + ## Installation 10 + 11 + The `wonka` package from `npm` is all you need to install to use 12 + Wonka. The process is the same with `yarn` and `esy`. 13 + 14 + ```bash 15 + yarn add wonka 16 + # or with npm: 17 + npm install --save wonka 18 + # or with esy: 19 + esy add wonka 20 + ``` 21 + 22 + For **JavaScript projects**, the package contains both CommonJS and 23 + ES Modules bundles. For Flow and TypeScript the package also contains 24 + typings files already, so if you're using either you're already done and 25 + ready to go. 26 + 27 + If you're using **BuckleScript** or `bs-native` you will need to add `"wonka"` 28 + to your `bs-dependencies` in your `bsconfig.json` configuration file: 29 + 30 + ```diff 31 + { 32 + "name": "<some_name>", 33 + "version": "0.1.0", 34 + "sources": ["src"], 35 + "bsc-flags": ["-bs-super-errors"], 36 + "bs-dependencies": [ 37 + + "wonka" 38 + ] 39 + } 40 + ``` 41 + 42 + If you're using **Dune** and **Esy** you will need to add `wonka` to 43 + your `libraries` entry in the respective `dune` configuration file: 44 + 45 + ```diff 46 + (library 47 + (name some_name) 48 + (public_name some_name) 49 + + (libraries wonka) 50 + ) 51 + ``` 52 + 53 + ## Usage with JavaScript 54 + 55 + In most cases you'll simply import or require `wonka` and use its exposed 56 + methods and utilities. In both CommonJS and ES Modules the Wonka package 57 + simply exposes all its utilities. 58 + 59 + ```js 60 + // With CommonJS 61 + const { fromArray } = require('wonka'); 62 + // With ES Modules 63 + import { fromArray } from 'wonka'; 64 + ``` 65 + 66 + There are also some special operators in Wonka that will only be exposed in 67 + Web/JavaScript environments, like `fromPromise`, `toPromise`, 68 + or `fromEvent`, or even `debounce` and `throttle`. 69 + In TypeScript and Flow the typings also expose all types. 70 + 71 + There's also a special utility in JavaScript environments to replace the pipeline 72 + operator. This function is called `pipe` and simply calls functions that it's 73 + being passed in order with the previous return value. 74 + 75 + ```js 76 + import { pipe } from 'wonka'; 77 + 78 + const output = pipe( 79 + 'test', 80 + x => x + ' this', 81 + x => x.toUpperCase() 82 + ); 83 + 84 + output; // "TEST THIS" 85 + ``` 86 + 87 + As shown above, the `pipe` function takes the first argument and passes it 88 + in order to the other function arguments. The return value of one function will 89 + be passed on to the next function. 90 + 91 + In TypeScript and Flow the `pipe` function is also typed to handle all generics 92 + in Wonka utilities correctly. Using it will ensure that most of the time you won't 93 + have to specify the types of any generics manually. 94 + 95 + If you're using Babel and the [pipeline proposal plugin](https://babeljs.io/docs/en/babel-plugin-proposal-pipeline-operator), you can just use 96 + the pipeline operator to do the same and not use the `pipe` helper. 97 + 98 + ## Usage with Reason 99 + 100 + Everything in the Wonka package is exposed under a single module called `Wonka`. 101 + This module also contains `Wonka.Types`, which contains all internal types of the Wonka 102 + library, but you will typically not need it. 103 + 104 + In `BuckleScript` when you're compiling to JavaScript you will also have access to 105 + more utilities like `fromPromise`, `toPromise`, `fromEvent`, or even `debounce` and `throttle`. 106 + These utilities are missing in native compilation, like Dune or `bsb-native`, since they're 107 + relying on JavaScript APIs like Promises, `window.addEventListener`, and `setTimeout`. 108 + 109 + When using Wonka you'd simply either open the module and use its utilities or just 110 + access them from the `Wonka` module: 111 + 112 + ```reason 113 + Wonka.fromValue("test") 114 + |> Wonka.map((.x) => x ++ " this") 115 + |> Wonka.forEach((.x) => print_endline(x)); 116 + ``` 117 + 118 + It's worth noting that most callbacks in Wonka need to be explicitly uncurried, since 119 + this will help them compile cleanly to JavaScript.
+46 -1
docs/index.md
··· 3 3 order: 0 4 4 --- 5 5 6 - This is Wonka! 6 + Wonka is a lightweight iterable and observable library loosely based on 7 + the [callbag spec](https://github.com/callbag/callbag). It exposes a set of helpers to create streams, 8 + which are sources of multiple values, which allow you to create, transform 9 + and consume event streams or iterable sets of data. 10 + 11 + ## What it is 12 + 13 + Wonka is a library for streams _and_ iterables that behaves predictably 14 + and can be used for many problems where you're dealing with streams of 15 + values, asynchronous or not. 16 + 17 + It's similar to [RxJS](https://github.com/ReactiveX/rxjs) in that it enables asynchronous programming with 18 + observable streams, with an API that looks like functional programming on 19 + iterables, but it's also similar to [IxJS](https://github.com/ReactiveX/IxJS) since Wonka streams will run 20 + synchronously if an iterable source runs synchronously. 21 + 22 + It also comes with many operators that users from [RxJS](https://github.com/ReactiveX/rxjs) will be used to. 23 + 24 + ## Compatibility 25 + 26 + Wonka is written in [Reason](https://reasonml.github.io/), a dialect of OCaml, and can hence be used 27 + for native applications. It is also compiled using [BuckleScript](https://bucklescript.github.io) to plain 28 + JavaScript and has typings for [TypeScript](https://www.typescriptlang.org/) and [Flow](https://flow.org/). 29 + 30 + This means that out of the box Wonka is usable in any project that use the following: 31 + 32 + - Plain JavaScript 33 + - TypeScript 34 + - Flow 35 + - Reason/OCaml with BuckleScript 36 + - Reason/OCaml with `bs-native` 37 + - Reason/OCaml with Dune and Esy 38 + 39 + In summary, Wonka provides a consistent interface in and works across 40 + TypeScript/Flow/Reason/OCaml environments with full type safety. 41 + 42 + ## About the docs 43 + 44 + As mentioned in the prior section, Wonka supports not one but a couple of 45 + environments and languages. To accommodate for this, most of the docs 46 + are written with examples and sections for TypeScript and Reason. 47 + 48 + We don't provide examples in most parts of the docs for Flow and OCaml because 49 + their respective usage is almost identical to TypeScript and Reason, so for 50 + the most part the examples mostly deal with the differences between a 51 + TypeScript and a Reason project.