UNPKG

72.7 kBMarkdownView Raw
1
2# Lib0 [![Build Status](https://travis-ci.com/dmonad/lib0.svg?branch=main)](https://travis-ci.com/dmonad/lib0)
3> Monorepo of isomorphic utility functions
4
5This library is meant to replace all global JavaScript functions with isomorphic module imports. Additionally, it implements several performance-oriented utility modules. Most noteworthy are the binary encoding/decoding modules **[lib0/encoding]** / **[lib0/decoding]**, the randomized testing framework **[lib0/testing]**, the fast Pseudo Random Number Generator **[lib0/PRNG]**, the small socket.io alternative **[lib0/websocket]**, and the logging module **[lib0/logging]** that allows colorized logging in all environments. Lib0 has only one dependency, which is also from the author of lib0. If lib0 is transpiled with rollup or webpack, very little code is produced because of the way that it is written. All exports are pure and are removed by transpilers that support dead code elimination. Here is an example of how dead code elemination and mangling optimizes code from lib0:
6
7```js
8// How the code is optimized by transpilers:
9
10// lib0/json.js
11export const stringify = JSON.stringify
12export const parse = JSON.parse
13
14// index.js
15import * as json from 'lib0/json'
16export const f = (arg1, arg2) => json.stringify(arg1) + json.stringify(arg2)
17
18// compiled with rollup and uglifyjs:
19const s=JSON.stringify,f=(a,b)=>s(a)+s(b)
20export {f}
21```
22
23## Performance resources
24
25Each function in this library is tested thoroughly and is not deoptimized by v8 (except some logging and comparison functions that can't be implemented without deoptimizations). This library implements its own test suite that is designed for randomized testing and inspecting performance issues.
26
27* `node --trace-deop` and `node --trace-opt`
28* https://youtu.be/IFWulQnM5E0 Good intro video
29* https://github.com/thlorenz/v8-perf
30* https://github.com/thlorenz/deoptigate - A great tool for investigating deoptimizations
31* https://github.com/vhf/v8-bailout-reasons - Description of some deopt messages
32
33## Code style
34
35The code style might be a bit different from what you are used to. Stay open. Most of the design choices have been thought through. The purpose of this code style is to create code that is optimized by the compiler and that results in small code bundles when used with common module bundlers. Keep that in mind when reading the library.
36
37* Modules should only export pure functions and constants. This way the module bundler can eliminate dead code. The statement `const x = someCondition ? A : B` cannot be eleminated, because it is tied to a condition.
38* Use Classes for structuring data. Classes are well supported by jsdoc and are immediately optimized by the compiler. I.e. prefer `class Coord { constructor (x, y) { this.x = x; this.y = y} }` instead of `{ x: x, y: y }`, because the compiler needs to be assured that the order of properties does not change. `{ y: y, x: x }` has a different hidden class than `{ x: x, y: y }`, which will lead to code deoptimizations if their use is alternated.
39* The user of your module should never create data objects with the `new` keyword. Prefer exporting factory functions like `const createCoordinate = (x, y) => new Coord(x, y)`.
40* The use of class methods is discouraged, because method names can't be mangled or removed by dead code elimination.
41* The only acceptable use of methods is when two objects implement functionality differently.
42 E.g. `class Duck { eat () { swallow() } }` and `class Cow { eat () { chew() } }` have the
43 same signature, but implement it differently.
44* Prefer `const` variable declarations. Use `let` only in loops. `const` always leads to easier code.
45* Keep the potential execution stack small and compartmentalized. Nobody wants to debug spaghetti code.
46* Give proper names to your functions and ask yourself if you would know what the function does if you saw it in the execution stack.
47* Avoid recursion. There is a stack limit in most browsers and not every recursive function is optimized by the compiler.
48* Semicolons are superfluous. Lint with https://standardjs.com/
49
50## Using lib0
51
52`lib0` contains isomorphic modules that work in nodejs, the browser, and other environments. It exports modules as the `commonjs` and the new `esm module` format.
53
54If possible,
55
56**ESM module**
57```js
58import module from 'lib0/[module]' // automatically resolves to lib0/[module].js
59```
60
61**CommonJS**
62```js
63require('lib0/[module]') // automatically resolves to lib0/dist/[module].cjs
64```
65
66**Manual**
67
68Automatically resolving to `commonjs` and `esm modules` is implemented using *conditional exports* which is available in `node>=v12`. If support for older versions is required, then it is recommended to define the location of the module manually:
69
70```js
71import module from 'lib0/[module].js'
72// require('lib0/dist/[module].cjs')
73```
74
75## Modules
76
77<details><summary><b>[lib0/array]</b> Utility module to work with Arrays.</summary>
78<pre>import * as array from 'lib0/array'</pre>
79<dl>
80<b><code>array.last(arr: Array&lt;L&gt;): L</code></b><br>
81<dd><p>Return the last element of an array. The element must exist</p></dd>
82<b><code>array.create(): Array&lt;C&gt;</code></b><br>
83<b><code>array.copy(a: Array&lt;D&gt;): Array&lt;D&gt;</code></b><br>
84<b><code>array.appendTo(dest: Array&lt;M&gt;, src: Array&lt;M&gt;)</code></b><br>
85<dd><p>Append elements from src to dest</p></dd>
86<b><code>array.from(arraylike: ArrayLike&lt;T&gt;|Iterable&lt;T&gt;): T</code></b><br>
87<dd><p>Transforms something array-like to an actual Array.</p></dd>
88<b><code>array.every(arr: Array&lt;ITEM&gt;, f: function(ITEM, number, Array&lt;ITEM&gt;):boolean): boolean</code></b><br>
89<dd><p>True iff condition holds on every element in the Array.</p></dd>
90<b><code>array.some(arr: Array&lt;S&gt;, f: function(S, number, Array&lt;S&gt;):boolean): boolean</code></b><br>
91<dd><p>True iff condition holds on some element in the Array.</p></dd>
92<b><code>array.equalFlat(a: Array&lt;ELEM&gt;, b: Array&lt;ELEM&gt;): boolean</code></b><br>
93<b><code>array.flatten(arr: Array&lt;Array&lt;ELEM&gt;&gt;): Array&lt;ELEM&gt;</code></b><br>
94<b><code>array.isArray</code></b><br>
95</dl>
96</details>
97<details><summary><b>[lib0/binary]</b> Binary data constants.</summary>
98<pre>import * as binary from 'lib0/binary'</pre>
99<dl>
100<b><code>binary.BIT1: number</code></b><br>
101<dd><p>n-th bit activated.</p></dd>
102<b><code>binary.BIT2</code></b><br>
103<b><code>binary.BIT3</code></b><br>
104<b><code>binary.BIT4</code></b><br>
105<b><code>binary.BIT5</code></b><br>
106<b><code>binary.BIT6</code></b><br>
107<b><code>binary.BIT7</code></b><br>
108<b><code>binary.BIT8</code></b><br>
109<b><code>binary.BIT9</code></b><br>
110<b><code>binary.BIT10</code></b><br>
111<b><code>binary.BIT11</code></b><br>
112<b><code>binary.BIT12</code></b><br>
113<b><code>binary.BIT13</code></b><br>
114<b><code>binary.BIT14</code></b><br>
115<b><code>binary.BIT15</code></b><br>
116<b><code>binary.BIT16</code></b><br>
117<b><code>binary.BIT17</code></b><br>
118<b><code>binary.BIT18</code></b><br>
119<b><code>binary.BIT19</code></b><br>
120<b><code>binary.BIT20</code></b><br>
121<b><code>binary.BIT21</code></b><br>
122<b><code>binary.BIT22</code></b><br>
123<b><code>binary.BIT23</code></b><br>
124<b><code>binary.BIT24</code></b><br>
125<b><code>binary.BIT25</code></b><br>
126<b><code>binary.BIT26</code></b><br>
127<b><code>binary.BIT27</code></b><br>
128<b><code>binary.BIT28</code></b><br>
129<b><code>binary.BIT29</code></b><br>
130<b><code>binary.BIT30</code></b><br>
131<b><code>binary.BIT31</code></b><br>
132<b><code>binary.BIT32</code></b><br>
133<b><code>binary.BITS0: number</code></b><br>
134<dd><p>First n bits activated.</p></dd>
135<b><code>binary.BITS1</code></b><br>
136<b><code>binary.BITS2</code></b><br>
137<b><code>binary.BITS3</code></b><br>
138<b><code>binary.BITS4</code></b><br>
139<b><code>binary.BITS5</code></b><br>
140<b><code>binary.BITS6</code></b><br>
141<b><code>binary.BITS7</code></b><br>
142<b><code>binary.BITS8</code></b><br>
143<b><code>binary.BITS9</code></b><br>
144<b><code>binary.BITS10</code></b><br>
145<b><code>binary.BITS11</code></b><br>
146<b><code>binary.BITS12</code></b><br>
147<b><code>binary.BITS13</code></b><br>
148<b><code>binary.BITS14</code></b><br>
149<b><code>binary.BITS15</code></b><br>
150<b><code>binary.BITS16</code></b><br>
151<b><code>binary.BITS17</code></b><br>
152<b><code>binary.BITS18</code></b><br>
153<b><code>binary.BITS19</code></b><br>
154<b><code>binary.BITS20</code></b><br>
155<b><code>binary.BITS21</code></b><br>
156<b><code>binary.BITS22</code></b><br>
157<b><code>binary.BITS23</code></b><br>
158<b><code>binary.BITS24</code></b><br>
159<b><code>binary.BITS25</code></b><br>
160<b><code>binary.BITS26</code></b><br>
161<b><code>binary.BITS27</code></b><br>
162<b><code>binary.BITS28</code></b><br>
163<b><code>binary.BITS29</code></b><br>
164<b><code>binary.BITS30</code></b><br>
165<b><code>binary.BITS31: number</code></b><br>
166<b><code>binary.BITS32: number</code></b><br>
167</dl>
168</details>
169<details><summary><b>[lib0/broadcastchannel]</b> Helpers for cross-tab communication using broadcastchannel with LocalStorage fallback.</summary>
170<pre>import * as broadcastchannel from 'lib0/broadcastchannel'</pre>
171
172<pre class="prettyprint source lang-js"><code>// In browser window A:
173broadcastchannel.subscribe('my events', data => console.log(data))
174broadcastchannel.publish('my events', 'Hello world!') // => A: 'Hello world!' fires synchronously in same tab
175
176// In browser window B:
177broadcastchannel.publish('my events', 'hello from tab B') // => A: 'hello from tab B'
178</code></pre>
179<dl>
180<b><code>broadcastchannel.subscribe(room: string, f: function(any, any):any)</code></b><br>
181<dd><p>Subscribe to global <code>publish</code> events.</p></dd>
182<b><code>broadcastchannel.unsubscribe(room: string, f: function(any, any):any)</code></b><br>
183<dd><p>Unsubscribe from <code>publish</code> global events.</p></dd>
184<b><code>broadcastchannel.publish(room: string, data: any, origin: any)</code></b><br>
185<dd><p>Publish data to all subscribers (including subscribers on this tab)</p></dd>
186</dl>
187</details>
188<details><summary><b>[lib0/buffer]</b> Utility functions to work with buffers (Uint8Array).</summary>
189<pre>import * as buffer from 'lib0/buffer'</pre>
190<dl>
191<b><code>buffer.createUint8ArrayFromLen(len: number)</code></b><br>
192<b><code>buffer.createUint8ArrayViewFromArrayBuffer(buffer: ArrayBuffer, byteOffset: number, length: number)</code></b><br>
193<dd><p>Create Uint8Array with initial content from buffer</p></dd>
194<b><code>buffer.createUint8ArrayFromArrayBuffer(buffer: ArrayBuffer)</code></b><br>
195<dd><p>Create Uint8Array with initial content from buffer</p></dd>
196<b><code>buffer.toBase64</code></b><br>
197<b><code>buffer.fromBase64</code></b><br>
198<b><code>buffer.copyUint8Array(uint8Array: Uint8Array): Uint8Array</code></b><br>
199<dd><p>Copy the content of an Uint8Array view to a new ArrayBuffer.</p></dd>
200<b><code>buffer.encodeAny(data: any): Uint8Array</code></b><br>
201<dd><p>Encode anything as a UInt8Array. It's a pun on typescripts's <code>any</code> type.
202See encoding.writeAny for more information.</p></dd>
203<b><code>buffer.decodeAny(buf: Uint8Array): any</code></b><br>
204<dd><p>Decode an any-encoded value.</p></dd>
205</dl>
206</details>
207<details><summary><b>[lib0/cache]</b> An implementation of a map which has keys that expire.</summary>
208<pre>import * as cache from 'lib0/cache'</pre>
209<dl>
210<b><code>new cache.Cache(timeout: number)</code></b><br>
211<b><code>cache.removeStale(cache: module:cache.Cache&lt;K, V&gt;): number</code></b><br>
212<b><code>cache.set(cache: module:cache.Cache&lt;K, V&gt;, key: K, value: V)</code></b><br>
213<b><code>cache.get(cache: module:cache.Cache&lt;K, V&gt;, key: K): V | undefined</code></b><br>
214<b><code>cache.refreshTimeout(cache: module:cache.Cache&lt;K, V&gt;, key: K)</code></b><br>
215<b><code>cache.getAsync(cache: module:cache.Cache&lt;K, V&gt;, key: K): V | Promise&lt;V&gt; | undefined</code></b><br>
216<dd><p>Works well in conjunktion with setIfUndefined which has an async init function.
217Using getAsync &amp; setIfUndefined ensures that the init function is only called once.</p></dd>
218<b><code>cache.remove(cache: module:cache.Cache&lt;K, V&gt;, key: K)</code></b><br>
219<b><code>cache.setIfUndefined(cache: module:cache.Cache&lt;K, V&gt;, key: K, init: function():Promise&lt;V&gt;, removeNull: boolean): Promise&lt;V&gt; | V</code></b><br>
220<b><code>cache.create(timeout: number)</code></b><br>
221</dl>
222</details>
223<details><summary><b>[lib0/component]</b> Web components.</summary>
224<pre>import * as component from 'lib0/component'</pre>
225<dl>
226<b><code>component.registry: CustomElementRegistry</code></b><br>
227<b><code>component.define(name: string, constr: any, opts: ElementDefinitionOptions)</code></b><br>
228<b><code>component.whenDefined(name: string): Promise&lt;CustomElementConstructor&gt;</code></b><br>
229<b><code>new component.Lib0Component(state: S)</code></b><br>
230<b><code>component.Lib0Component#state: S|null</code></b><br>
231<b><code>component.Lib0Component#setState(state: S, forceStateUpdate: boolean)</code></b><br>
232<b><code>component.Lib0Component#updateState(stateUpdate: any)</code></b><br>
233<b><code>component.createComponent(name: string, cnf: module:component~CONF&lt;T&gt;): Class&lt;module:component.Lib0Component&gt;</code></b><br>
234<b><code>component.createComponentDefiner(definer: function)</code></b><br>
235<b><code>component.defineListComponent</code></b><br>
236<b><code>component.defineLazyLoadingComponent</code></b><br>
237</dl>
238</details>
239<details><summary><b>[lib0/conditions]</b> Often used conditions.</summary>
240<pre>import * as conditions from 'lib0/conditions'</pre>
241<dl>
242<b><code>conditions.undefinedToNull</code></b><br>
243</dl>
244</details>
245<details><summary><b>[lib0/decoding]</b> Efficient schema-less binary decoding with support for variable length encoding.</summary>
246<pre>import * as decoding from 'lib0/decoding'</pre>
247
248<p>Use [lib0/decoding] with [lib0/encoding]. Every encoding function has a corresponding decoding function.</p>
249<p>Encodes numbers in little-endian order (least to most significant byte order)
250and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
251which is also used in Protocol Buffers.</p>
252<pre class="prettyprint source lang-js"><code>// encoding step
253const encoder = new encoding.createEncoder()
254encoding.writeVarUint(encoder, 256)
255encoding.writeVarString(encoder, 'Hello world!')
256const buf = encoding.toUint8Array(encoder)
257</code></pre>
258<pre class="prettyprint source lang-js"><code>// decoding step
259const decoder = new decoding.createDecoder(buf)
260decoding.readVarUint(decoder) // => 256
261decoding.readVarString(decoder) // => 'Hello world!'
262decoding.hasContent(decoder) // => false - all data is read
263</code></pre>
264<dl>
265<b><code>new decoding.Decoder(uint8Array: Uint8Array)</code></b><br>
266<dd><p>A Decoder handles the decoding of an Uint8Array.</p></dd>
267<b><code>decoding.Decoder#arr: Uint8Array</code></b><br>
268<dd><p>Decoding target.</p></dd>
269<b><code>decoding.Decoder#pos: number</code></b><br>
270<dd><p>Current decoding position.</p></dd>
271<b><code>decoding.createDecoder(uint8Array: Uint8Array): module:decoding.Decoder</code></b><br>
272<b><code>decoding.hasContent(decoder: module:decoding.Decoder): boolean</code></b><br>
273<b><code>decoding.clone(decoder: module:decoding.Decoder, newPos: number): module:decoding.Decoder</code></b><br>
274<dd><p>Clone a decoder instance.
275Optionally set a new position parameter.</p></dd>
276<b><code>decoding.readUint8Array(decoder: module:decoding.Decoder, len: number): Uint8Array</code></b><br>
277<dd><p>Create an Uint8Array view of the next <code>len</code> bytes and advance the position by <code>len</code>.</p>
278<p>Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
279Use <code>buffer.copyUint8Array</code> to copy the result into a new Uint8Array.</p></dd>
280<b><code>decoding.readVarUint8Array(decoder: module:decoding.Decoder): Uint8Array</code></b><br>
281<dd><p>Read variable length Uint8Array.</p>
282<p>Important: The Uint8Array still points to the underlying ArrayBuffer. Make sure to discard the result as soon as possible to prevent any memory leaks.
283Use <code>buffer.copyUint8Array</code> to copy the result into a new Uint8Array.</p></dd>
284<b><code>decoding.readTailAsUint8Array(decoder: module:decoding.Decoder): Uint8Array</code></b><br>
285<dd><p>Read the rest of the content as an ArrayBuffer</p></dd>
286<b><code>decoding.skip8(decoder: module:decoding.Decoder): number</code></b><br>
287<dd><p>Skip one byte, jump to the next position.</p></dd>
288<b><code>decoding.readUint8(decoder: module:decoding.Decoder): number</code></b><br>
289<dd><p>Read one byte as unsigned integer.</p></dd>
290<b><code>decoding.readUint16(decoder: module:decoding.Decoder): number</code></b><br>
291<dd><p>Read 2 bytes as unsigned integer.</p></dd>
292<b><code>decoding.readUint32(decoder: module:decoding.Decoder): number</code></b><br>
293<dd><p>Read 4 bytes as unsigned integer.</p></dd>
294<b><code>decoding.readUint32BigEndian(decoder: module:decoding.Decoder): number</code></b><br>
295<dd><p>Read 4 bytes as unsigned integer in big endian order.
296(most significant byte first)</p></dd>
297<b><code>decoding.peekUint8(decoder: module:decoding.Decoder): number</code></b><br>
298<dd><p>Look ahead without incrementing the position
299to the next byte and read it as unsigned integer.</p></dd>
300<b><code>decoding.peekUint16(decoder: module:decoding.Decoder): number</code></b><br>
301<dd><p>Look ahead without incrementing the position
302to the next byte and read it as unsigned integer.</p></dd>
303<b><code>decoding.peekUint32(decoder: module:decoding.Decoder): number</code></b><br>
304<dd><p>Look ahead without incrementing the position
305to the next byte and read it as unsigned integer.</p></dd>
306<b><code>decoding.readVarUint(decoder: module:decoding.Decoder): number</code></b><br>
307<dd><p>Read unsigned integer (32bit) with variable length.
3081/8th of the storage is used as encoding overhead.</p>
309<ul>
310<li>numbers &lt; 2^7 is stored in one bytlength</li>
311<li>numbers &lt; 2^14 is stored in two bylength</li>
312</ul></dd>
313<b><code>decoding.readVarInt(decoder: module:decoding.Decoder): number</code></b><br>
314<dd><p>Read signed integer (32bit) with variable length.
3151/8th of the storage is used as encoding overhead.</p>
316<ul>
317<li>numbers &lt; 2^7 is stored in one bytlength</li>
318<li>numbers &lt; 2^14 is stored in two bylength</li>
319</ul></dd>
320<b><code>decoding.peekVarUint(decoder: module:decoding.Decoder): number</code></b><br>
321<dd><p>Look ahead and read varUint without incrementing position</p></dd>
322<b><code>decoding.peekVarInt(decoder: module:decoding.Decoder): number</code></b><br>
323<dd><p>Look ahead and read varUint without incrementing position</p></dd>
324<b><code>decoding.readVarString</code></b><br>
325<b><code>decoding.peekVarString(decoder: module:decoding.Decoder): string</code></b><br>
326<dd><p>Look ahead and read varString without incrementing position</p></dd>
327<b><code>decoding.readFromDataView(decoder: module:decoding.Decoder, len: number): DataView</code></b><br>
328<b><code>decoding.readFloat32(decoder: module:decoding.Decoder)</code></b><br>
329<b><code>decoding.readFloat64(decoder: module:decoding.Decoder)</code></b><br>
330<b><code>decoding.readBigInt64(decoder: module:decoding.Decoder)</code></b><br>
331<b><code>decoding.readBigUint64(decoder: module:decoding.Decoder)</code></b><br>
332<b><code>decoding.readAny(decoder: module:decoding.Decoder)</code></b><br>
333<b><code>new decoding.RleDecoder(uint8Array: Uint8Array, reader: function(module:decoding.Decoder):T)</code></b><br>
334<dd><p>T must not be null.</p></dd>
335<b><code>decoding.RleDecoder#s: T|null</code></b><br>
336<dd><p>Current state</p></dd>
337<b><code>decoding.RleDecoder#read()</code></b><br>
338<b><code>decoding.RleDecoder#s: T</code></b><br>
339<b><code>new decoding.IntDiffDecoder(uint8Array: Uint8Array, start: number)</code></b><br>
340<b><code>decoding.IntDiffDecoder#s: number</code></b><br>
341<dd><p>Current state</p></dd>
342<b><code>decoding.IntDiffDecoder#read(): number</code></b><br>
343<b><code>new decoding.RleIntDiffDecoder(uint8Array: Uint8Array, start: number)</code></b><br>
344<b><code>decoding.RleIntDiffDecoder#s: number</code></b><br>
345<dd><p>Current state</p></dd>
346<b><code>decoding.RleIntDiffDecoder#read(): number</code></b><br>
347<b><code>decoding.RleIntDiffDecoder#s: number</code></b><br>
348<b><code>new decoding.UintOptRleDecoder(uint8Array: Uint8Array)</code></b><br>
349<b><code>decoding.UintOptRleDecoder#s: number</code></b><br>
350<b><code>decoding.UintOptRleDecoder#read()</code></b><br>
351<b><code>decoding.UintOptRleDecoder#s: number</code></b><br>
352<b><code>new decoding.IncUintOptRleDecoder(uint8Array: Uint8Array)</code></b><br>
353<b><code>decoding.IncUintOptRleDecoder#s: number</code></b><br>
354<b><code>decoding.IncUintOptRleDecoder#read()</code></b><br>
355<b><code>new decoding.IntDiffOptRleDecoder(uint8Array: Uint8Array)</code></b><br>
356<b><code>decoding.IntDiffOptRleDecoder#s: number</code></b><br>
357<b><code>decoding.IntDiffOptRleDecoder#read(): number</code></b><br>
358<b><code>new decoding.StringDecoder(uint8Array: Uint8Array)</code></b><br>
359<b><code>decoding.StringDecoder#spos: number</code></b><br>
360<b><code>decoding.StringDecoder#read(): string</code></b><br>
361<b><code>decoding.RleDecoder#arr: Uint8Array</code></b><br>
362<dd><p>Decoding target.</p></dd>
363<b><code>decoding.RleDecoder#pos: number</code></b><br>
364<dd><p>Current decoding position.</p></dd>
365<b><code>decoding.IntDiffDecoder#arr: Uint8Array</code></b><br>
366<dd><p>Decoding target.</p></dd>
367<b><code>decoding.IntDiffDecoder#pos: number</code></b><br>
368<dd><p>Current decoding position.</p></dd>
369<b><code>decoding.RleIntDiffDecoder#arr: Uint8Array</code></b><br>
370<dd><p>Decoding target.</p></dd>
371<b><code>decoding.RleIntDiffDecoder#pos: number</code></b><br>
372<dd><p>Current decoding position.</p></dd>
373<b><code>decoding.UintOptRleDecoder#arr: Uint8Array</code></b><br>
374<dd><p>Decoding target.</p></dd>
375<b><code>decoding.UintOptRleDecoder#pos: number</code></b><br>
376<dd><p>Current decoding position.</p></dd>
377<b><code>decoding.IncUintOptRleDecoder#arr: Uint8Array</code></b><br>
378<dd><p>Decoding target.</p></dd>
379<b><code>decoding.IncUintOptRleDecoder#pos: number</code></b><br>
380<dd><p>Current decoding position.</p></dd>
381<b><code>decoding.IntDiffOptRleDecoder#arr: Uint8Array</code></b><br>
382<dd><p>Decoding target.</p></dd>
383<b><code>decoding.IntDiffOptRleDecoder#pos: number</code></b><br>
384<dd><p>Current decoding position.</p></dd>
385</dl>
386</details>
387<details><summary><b>[lib0/diff]</b> Efficient diffs.</summary>
388<pre>import * as diff from 'lib0/diff'</pre>
389<dl>
390<b><code>diff.simpleDiffString(a: string, b: string): module:diff~SimpleDiff&lt;string&gt;</code></b><br>
391<dd><p>Create a diff between two strings. This diff implementation is highly
392efficient, but not very sophisticated.</p></dd>
393<b><code>diff.simpleDiff</code></b><br>
394<b><code>diff.simpleDiffArray(a: Array&lt;T&gt;, b: Array&lt;T&gt;, compare: function(T, T):boolean): module:diff~SimpleDiff&lt;Array&lt;T&gt;&gt;</code></b><br>
395<dd><p>Create a diff between two arrays. This diff implementation is highly
396efficient, but not very sophisticated.</p>
397<p>Note: This is basically the same function as above. Another function was created so that the runtime
398can better optimize these function calls.</p></dd>
399<b><code>diff.simpleDiffStringWithCursor(a: string, b: string, cursor: number)</code></b><br>
400<dd><p>Diff text and try to diff at the current cursor position.</p></dd>
401</dl>
402</details>
403<details><summary><b>[lib0/dom]</b> Utility module to work with the DOM.</summary>
404<pre>import * as dom from 'lib0/dom'</pre>
405<dl>
406<b><code>dom.doc: Document</code></b><br>
407<b><code>dom.createElement</code></b><br>
408<b><code>dom.createDocumentFragment</code></b><br>
409<b><code>dom.createTextNode</code></b><br>
410<b><code>dom.domParser</code></b><br>
411<b><code>dom.emitCustomEvent</code></b><br>
412<b><code>dom.setAttributes</code></b><br>
413<b><code>dom.setAttributesMap</code></b><br>
414<b><code>dom.fragment</code></b><br>
415<b><code>dom.append</code></b><br>
416<b><code>dom.remove</code></b><br>
417<b><code>dom.addEventListener</code></b><br>
418<b><code>dom.removeEventListener</code></b><br>
419<b><code>dom.addEventListeners</code></b><br>
420<b><code>dom.removeEventListeners</code></b><br>
421<b><code>dom.element</code></b><br>
422<b><code>dom.canvas</code></b><br>
423<b><code>dom.text</code></b><br>
424<b><code>dom.pairToStyleString</code></b><br>
425<b><code>dom.pairsToStyleString</code></b><br>
426<b><code>dom.mapToStyleString</code></b><br>
427<b><code>dom.querySelector</code></b><br>
428<b><code>dom.querySelectorAll</code></b><br>
429<b><code>dom.getElementById</code></b><br>
430<b><code>dom.parseFragment</code></b><br>
431<b><code>dom.childNodes: any</code></b><br>
432<b><code>dom.parseElement</code></b><br>
433<b><code>dom.replaceWith</code></b><br>
434<b><code>dom.insertBefore</code></b><br>
435<b><code>dom.appendChild</code></b><br>
436<b><code>dom.ELEMENT_NODE</code></b><br>
437<b><code>dom.TEXT_NODE</code></b><br>
438<b><code>dom.CDATA_SECTION_NODE</code></b><br>
439<b><code>dom.COMMENT_NODE</code></b><br>
440<b><code>dom.DOCUMENT_NODE</code></b><br>
441<b><code>dom.DOCUMENT_TYPE_NODE</code></b><br>
442<b><code>dom.DOCUMENT_FRAGMENT_NODE</code></b><br>
443<b><code>dom.checkNodeType(node: any, type: number)</code></b><br>
444<b><code>dom.isParentOf(parent: Node, child: HTMLElement)</code></b><br>
445</dl>
446</details>
447<details><summary><b>[lib0/encoding]</b> Efficient schema-less binary encoding with support for variable length encoding.</summary>
448<pre>import * as encoding from 'lib0/encoding'</pre>
449
450<p>Use [lib0/encoding] with [lib0/decoding]. Every encoding function has a corresponding decoding function.</p>
451<p>Encodes numbers in little-endian order (least to most significant byte order)
452and is compatible with Golang's binary encoding (https://golang.org/pkg/encoding/binary/)
453which is also used in Protocol Buffers.</p>
454<pre class="prettyprint source lang-js"><code>// encoding step
455const encoder = new encoding.createEncoder()
456encoding.writeVarUint(encoder, 256)
457encoding.writeVarString(encoder, 'Hello world!')
458const buf = encoding.toUint8Array(encoder)
459</code></pre>
460<pre class="prettyprint source lang-js"><code>// decoding step
461const decoder = new decoding.createDecoder(buf)
462decoding.readVarUint(decoder) // => 256
463decoding.readVarString(decoder) // => 'Hello world!'
464decoding.hasContent(decoder) // => false - all data is read
465</code></pre>
466<dl>
467<b><code>new encoding.Encoder()</code></b><br>
468<dd><p>A BinaryEncoder handles the encoding to an Uint8Array.</p></dd>
469<b><code>encoding.Encoder#bufs: Array&lt;Uint8Array&gt;</code></b><br>
470<b><code>encoding.createEncoder(): module:encoding.Encoder</code></b><br>
471<b><code>encoding.length(encoder: module:encoding.Encoder): number</code></b><br>
472<dd><p>The current length of the encoded data.</p></dd>
473<b><code>encoding.toUint8Array(encoder: module:encoding.Encoder): Uint8Array</code></b><br>
474<dd><p>Transform to Uint8Array.</p></dd>
475<b><code>encoding.verifyLen(encoder: module:encoding.Encoder, len: number)</code></b><br>
476<dd><p>Verify that it is possible to write <code>len</code> bytes wtihout checking. If
477necessary, a new Buffer with the required length is attached.</p></dd>
478<b><code>encoding.write(encoder: module:encoding.Encoder, num: number)</code></b><br>
479<dd><p>Write one byte to the encoder.</p></dd>
480<b><code>encoding.set(encoder: module:encoding.Encoder, pos: number, num: number)</code></b><br>
481<dd><p>Write one byte at a specific position.
482Position must already be written (i.e. encoder.length &gt; pos)</p></dd>
483<b><code>encoding.writeUint8(encoder: module:encoding.Encoder, num: number)</code></b><br>
484<dd><p>Write one byte as an unsigned integer.</p></dd>
485<b><code>encoding.setUint8(encoder: module:encoding.Encoder, pos: number, num: number)</code></b><br>
486<dd><p>Write one byte as an unsigned Integer at a specific location.</p></dd>
487<b><code>encoding.writeUint16(encoder: module:encoding.Encoder, num: number)</code></b><br>
488<dd><p>Write two bytes as an unsigned integer.</p></dd>
489<b><code>encoding.setUint16(encoder: module:encoding.Encoder, pos: number, num: number)</code></b><br>
490<dd><p>Write two bytes as an unsigned integer at a specific location.</p></dd>
491<b><code>encoding.writeUint32(encoder: module:encoding.Encoder, num: number)</code></b><br>
492<dd><p>Write two bytes as an unsigned integer</p></dd>
493<b><code>encoding.writeUint32BigEndian(encoder: module:encoding.Encoder, num: number)</code></b><br>
494<dd><p>Write two bytes as an unsigned integer in big endian order.
495(most significant byte first)</p></dd>
496<b><code>encoding.setUint32(encoder: module:encoding.Encoder, pos: number, num: number)</code></b><br>
497<dd><p>Write two bytes as an unsigned integer at a specific location.</p></dd>
498<b><code>encoding.writeVarUint(encoder: module:encoding.Encoder, num: number)</code></b><br>
499<dd><p>Write a variable length unsigned integer. Max encodable integer is 2^53.</p></dd>
500<b><code>encoding.writeVarInt(encoder: module:encoding.Encoder, num: number)</code></b><br>
501<dd><p>Write a variable length integer.</p>
502<p>We use the 7th bit instead for signaling that this is a negative number.</p></dd>
503<b><code>encoding.writeVarString</code></b><br>
504<b><code>encoding.writeBinaryEncoder(encoder: module:encoding.Encoder, append: module:encoding.Encoder)</code></b><br>
505<dd><p>Write the content of another Encoder.</p></dd>
506<b><code>encoding.writeUint8Array(encoder: module:encoding.Encoder, uint8Array: Uint8Array)</code></b><br>
507<dd><p>Append fixed-length Uint8Array to the encoder.</p></dd>
508<b><code>encoding.writeVarUint8Array(encoder: module:encoding.Encoder, uint8Array: Uint8Array)</code></b><br>
509<dd><p>Append an Uint8Array to Encoder.</p></dd>
510<b><code>encoding.writeOnDataView(encoder: module:encoding.Encoder, len: number): DataView</code></b><br>
511<dd><p>Create an DataView of the next <code>len</code> bytes. Use it to write data after
512calling this function.</p>
513<pre class="prettyprint source lang-js"><code>// write float32 using DataView
514const dv = writeOnDataView(encoder, 4)
515dv.setFloat32(0, 1.1)
516// read float32 using DataView
517const dv = readFromDataView(encoder, 4)
518dv.getFloat32(0) // => 1.100000023841858 (leaving it to the reader to find out why this is the correct result)
519</code></pre></dd>
520<b><code>encoding.writeFloat32(encoder: module:encoding.Encoder, num: number)</code></b><br>
521<b><code>encoding.writeFloat64(encoder: module:encoding.Encoder, num: number)</code></b><br>
522<b><code>encoding.writeBigInt64(encoder: module:encoding.Encoder, num: bigint)</code></b><br>
523<b><code>encoding.writeBigUint64(encoder: module:encoding.Encoder, num: bigint)</code></b><br>
524<b><code>encoding.writeAny(encoder: module:encoding.Encoder, data: undefined|null|number|bigint|boolean|string|Object&lt;string,any&gt;|Array&lt;any&gt;|Uint8Array)</code></b><br>
525<dd><p>Encode data with efficient binary format.</p>
526<p>Differences to JSON:
527• Transforms data to a binary format (not to a string)
528• Encodes undefined, NaN, and ArrayBuffer (these can't be represented in JSON)
529• Numbers are efficiently encoded either as a variable length integer, as a
53032 bit float, as a 64 bit float, or as a 64 bit bigint.</p>
531<p>Encoding table:</p>
532<table>
533<thead>
534<tr>
535<th>Data Type</th>
536<th>Prefix</th>
537<th>Encoding Method</th>
538<th>Comment</th>
539</tr>
540</thead>
541<tbody>
542<tr>
543<td>undefined</td>
544<td>127</td>
545<td></td>
546<td>Functions, symbol, and everything that cannot be identified is encoded as undefined</td>
547</tr>
548<tr>
549<td>null</td>
550<td>126</td>
551<td></td>
552<td></td>
553</tr>
554<tr>
555<td>integer</td>
556<td>125</td>
557<td>writeVarInt</td>
558<td>Only encodes 32 bit signed integers</td>
559</tr>
560<tr>
561<td>float32</td>
562<td>124</td>
563<td>writeFloat32</td>
564<td></td>
565</tr>
566<tr>
567<td>float64</td>
568<td>123</td>
569<td>writeFloat64</td>
570<td></td>
571</tr>
572<tr>
573<td>bigint</td>
574<td>122</td>
575<td>writeBigInt64</td>
576<td></td>
577</tr>
578<tr>
579<td>boolean (false)</td>
580<td>121</td>
581<td></td>
582<td>True and false are different data types so we save the following byte</td>
583</tr>
584<tr>
585<td>boolean (true)</td>
586<td>120</td>
587<td></td>
588<td>- 0b01111000 so the last bit determines whether true or false</td>
589</tr>
590<tr>
591<td>string</td>
592<td>119</td>
593<td>writeVarString</td>
594<td></td>
595</tr>
596<tr>
597<td>object&lt;string,any&gt;</td>
598<td>118</td>
599<td>custom</td>
600<td>Writes {length} then {length} key-value pairs</td>
601</tr>
602<tr>
603<td>array<any></td>
604<td>117</td>
605<td>custom</td>
606<td>Writes {length} then {length} json values</td>
607</tr>
608<tr>
609<td>Uint8Array</td>
610<td>116</td>
611<td>writeVarUint8Array</td>
612<td>We use Uint8Array for any kind of binary data</td>
613</tr>
614</tbody>
615</table>
616<p>Reasons for the decreasing prefix:
617We need the first bit for extendability (later we may want to encode the
618prefix with writeVarUint). The remaining 7 bits are divided as follows:
619[0-30] the beginning of the data range is used for custom purposes
620(defined by the function that uses this library)
621[31-127] the end of the data range is used for data encoding by
622lib0/encoding.js</p></dd>
623<b><code>new encoding.RleEncoder(writer: function(module:encoding.Encoder, T):void)</code></b><br>
624<dd><p>Now come a few stateful encoder that have their own classes.</p></dd>
625<b><code>encoding.RleEncoder#s: T|null</code></b><br>
626<dd><p>Current state</p></dd>
627<b><code>encoding.RleEncoder#write(v: T)</code></b><br>
628<b><code>new encoding.IntDiffEncoder(start: number)</code></b><br>
629<dd><p>Basic diff decoder using variable length encoding.</p>
630<p>Encodes the values [3, 1100, 1101, 1050, 0] to [3, 1097, 1, -51, -1050] using writeVarInt.</p></dd>
631<b><code>encoding.IntDiffEncoder#s: number</code></b><br>
632<dd><p>Current state</p></dd>
633<b><code>encoding.IntDiffEncoder#write(v: number)</code></b><br>
634<b><code>new encoding.RleIntDiffEncoder(start: number)</code></b><br>
635<dd><p>A combination of IntDiffEncoder and RleEncoder.</p>
636<p>Basically first writes the IntDiffEncoder and then counts duplicate diffs using RleEncoding.</p>
637<p>Encodes the values [1,1,1,2,3,4,5,6] as [1,1,0,2,1,5] (RLE([1,0,0,1,1,1,1,1]) ⇒ RleIntDiff[1,1,0,2,1,5])</p></dd>
638<b><code>encoding.RleIntDiffEncoder#s: number</code></b><br>
639<dd><p>Current state</p></dd>
640<b><code>encoding.RleIntDiffEncoder#write(v: number)</code></b><br>
641<b><code>new encoding.UintOptRleEncoder()</code></b><br>
642<dd><p>Optimized Rle encoder that does not suffer from the mentioned problem of the basic Rle encoder.</p>
643<p>Internally uses VarInt encoder to write unsigned integers. If the input occurs multiple times, we write
644write it as a negative number. The UintOptRleDecoder then understands that it needs to read a count.</p>
645<p>Encodes [1,2,3,3,3] as [1,2,-3,3] (once 1, once 2, three times 3)</p></dd>
646<b><code>encoding.UintOptRleEncoder#s: number</code></b><br>
647<b><code>encoding.UintOptRleEncoder#write(v: number)</code></b><br>
648<b><code>encoding.UintOptRleEncoder#toUint8Array()</code></b><br>
649<b><code>new encoding.IncUintOptRleEncoder()</code></b><br>
650<dd><p>Increasing Uint Optimized RLE Encoder</p>
651<p>The RLE encoder counts the number of same occurences of the same value.
652The IncUintOptRle encoder counts if the value increases.
653I.e. 7, 8, 9, 10 will be encoded as [-7, 4]. 1, 3, 5 will be encoded
654as [1, 3, 5].</p></dd>
655<b><code>encoding.IncUintOptRleEncoder#s: number</code></b><br>
656<b><code>encoding.IncUintOptRleEncoder#write(v: number)</code></b><br>
657<b><code>encoding.IncUintOptRleEncoder#toUint8Array()</code></b><br>
658<b><code>new encoding.IntDiffOptRleEncoder()</code></b><br>
659<dd><p>A combination of the IntDiffEncoder and the UintOptRleEncoder.</p>
660<p>The count approach is similar to the UintDiffOptRleEncoder, but instead of using the negative bitflag, it encodes
661in the LSB whether a count is to be read. Therefore this Encoder only supports 31 bit integers!</p>
662<p>Encodes [1, 2, 3, 2] as [3, 1, 6, -1] (more specifically [(1 &lt;&lt; 1) | 1, (3 &lt;&lt; 0) | 0, -1])</p>
663<p>Internally uses variable length encoding. Contrary to normal UintVar encoding, the first byte contains:</p>
664<ul>
665<li>1 bit that denotes whether the next value is a count (LSB)</li>
666<li>1 bit that denotes whether this value is negative (MSB - 1)</li>
667<li>1 bit that denotes whether to continue reading the variable length integer (MSB)</li>
668</ul>
669<p>Therefore, only five bits remain to encode diff ranges.</p>
670<p>Use this Encoder only when appropriate. In most cases, this is probably a bad idea.</p></dd>
671<b><code>encoding.IntDiffOptRleEncoder#s: number</code></b><br>
672<b><code>encoding.IntDiffOptRleEncoder#write(v: number)</code></b><br>
673<b><code>encoding.IntDiffOptRleEncoder#toUint8Array()</code></b><br>
674<b><code>new encoding.StringEncoder()</code></b><br>
675<dd><p>Optimized String Encoder.</p>
676<p>Encoding many small strings in a simple Encoder is not very efficient. The function call to decode a string takes some time and creates references that must be eventually deleted.
677In practice, when decoding several million small strings, the GC will kick in more and more often to collect orphaned string objects (or maybe there is another reason?).</p>
678<p>This string encoder solves the above problem. All strings are concatenated and written as a single string using a single encoding call.</p>
679<p>The lengths are encoded using a UintOptRleEncoder.</p></dd>
680<b><code>encoding.StringEncoder#sarr: Array&lt;string&gt;</code></b><br>
681<b><code>encoding.StringEncoder#write(string: string)</code></b><br>
682<b><code>encoding.StringEncoder#toUint8Array()</code></b><br>
683<b><code>encoding.RleEncoder#bufs: Array&lt;Uint8Array&gt;</code></b><br>
684<b><code>encoding.IntDiffEncoder#bufs: Array&lt;Uint8Array&gt;</code></b><br>
685<b><code>encoding.RleIntDiffEncoder#bufs: Array&lt;Uint8Array&gt;</code></b><br>
686</dl>
687</details>
688<details><summary><b>[lib0/map]</b> Isomorphic module to work access the environment (query params, env variables).</summary>
689<pre>import * as map from 'lib0/environment'</pre>
690<dl>
691<b><code>map.isNode</code></b><br>
692<b><code>map.isBrowser</code></b><br>
693<b><code>map.isMac</code></b><br>
694<b><code>map.hasParam</code></b><br>
695<b><code>map.getParam</code></b><br>
696<b><code>map.getVariable</code></b><br>
697<b><code>map.getConf(name: string): string|null</code></b><br>
698<b><code>map.hasConf</code></b><br>
699<b><code>map.production</code></b><br>
700</dl>
701</details>
702<details><summary><b>[lib0/error]</b> Error helpers.</summary>
703<pre>import * as error from 'lib0/error'</pre>
704<dl>
705<b><code>error.create(s: string): Error</code></b><br>
706<b><code>error.methodUnimplemented(): never</code></b><br>
707<b><code>error.unexpectedCase(): never</code></b><br>
708</dl>
709</details>
710<details><summary><b>[lib0/eventloop]</b> Utility module to work with EcmaScript's event loop.</summary>
711<pre>import * as eventloop from 'lib0/eventloop'</pre>
712<dl>
713<b><code>eventloop.enqueue(f: function():void)</code></b><br>
714<b><code>eventloop#destroy()</code></b><br>
715<b><code>eventloop.timeout(timeout: number, callback: function): module:eventloop~TimeoutObject</code></b><br>
716<b><code>eventloop.interval(timeout: number, callback: function): module:eventloop~TimeoutObject</code></b><br>
717<b><code>eventloop.Animation</code></b><br>
718<b><code>eventloop.animationFrame(cb: function(number):void): module:eventloop~TimeoutObject</code></b><br>
719<b><code>eventloop.idleCallback(cb: function): module:eventloop~TimeoutObject</code></b><br>
720<dd><p>Note: this is experimental and is probably only useful in browsers.</p></dd>
721<b><code>eventloop.createDebouncer(timeout: number): function(function():void):void</code></b><br>
722</dl>
723</details>
724<details><summary><b>[lib0/function]</b> Common functions and function call helpers.</summary>
725<pre>import * as function from 'lib0/function'</pre>
726<dl>
727<b><code>function.callAll(fs: Array&lt;function&gt;, args: Array&lt;any&gt;)</code></b><br>
728<dd><p>Calls all functions in <code>fs</code> with args. Only throws after all functions were called.</p></dd>
729<b><code>function.nop</code></b><br>
730<b><code>function.apply(f: function():T): T</code></b><br>
731<b><code>function.id(a: A): A</code></b><br>
732<b><code>function.equalityStrict(a: T, b: T): boolean</code></b><br>
733<b><code>function.equalityFlat(a: Array&lt;T&gt;|object, b: Array&lt;T&gt;|object): boolean</code></b><br>
734<b><code>function.equalityDeep(a: any, b: any): boolean</code></b><br>
735</dl>
736</details>
737<details><summary><b>[lib0/lib0]</b> Experimental method to import lib0.</summary>
738<pre>import * as lib0 from 'lib0/index'</pre>
739
740<p>Not recommended if the module bundler doesn't support dead code elimination.</p>
741<dl>
742</dl>
743</details>
744<details><summary><b>[lib0/indexeddb]</b> Helpers to work with IndexedDB.</summary>
745<pre>import * as indexeddb from 'lib0/indexeddb'</pre>
746<dl>
747<b><code>indexeddb.rtop(request: IDBRequest): Promise&lt;any&gt;</code></b><br>
748<dd><p>IDB Request to Promise transformer</p></dd>
749<b><code>indexeddb.openDB(name: string, initDB: function(IDBDatabase):any): Promise&lt;IDBDatabase&gt;</code></b><br>
750<b><code>indexeddb.deleteDB(name: string)</code></b><br>
751<b><code>indexeddb.createStores(db: IDBDatabase, definitions: Array&lt;Array&lt;string&gt;|Array&lt;string|IDBObjectStoreParameters|undefined&gt;&gt;)</code></b><br>
752<b><code>indexeddb.transact(db: IDBDatabase, stores: Array&lt;string&gt;, access: "readwrite"|"readonly"): Array&lt;IDBObjectStore&gt;</code></b><br>
753<b><code>indexeddb.count(store: IDBObjectStore, range: IDBKeyRange): Promise&lt;number&gt;</code></b><br>
754<b><code>indexeddb.get(store: IDBObjectStore, key: String | number | ArrayBuffer | Date | Array&lt;any&gt; ): Promise&lt;String | number | ArrayBuffer | Date | Array&lt;any&gt;&gt;</code></b><br>
755<b><code>indexeddb.del(store: IDBObjectStore, key: String | number | ArrayBuffer | Date | IDBKeyRange | Array&lt;any&gt; )</code></b><br>
756<b><code>indexeddb.put(store: IDBObjectStore, item: String | number | ArrayBuffer | Date | boolean, key: String | number | ArrayBuffer | Date | Array&lt;any&gt;)</code></b><br>
757<b><code>indexeddb.add(store: IDBObjectStore, item: String|number|ArrayBuffer|Date|boolean, key: String|number|ArrayBuffer|Date|Array.&lt;any&gt;): Promise&lt;any&gt;</code></b><br>
758<b><code>indexeddb.addAutoKey(store: IDBObjectStore, item: String|number|ArrayBuffer|Date): Promise&lt;number&gt;</code></b><br>
759<b><code>indexeddb.getAll(store: IDBObjectStore, range: IDBKeyRange): Promise&lt;Array&lt;any&gt;&gt;</code></b><br>
760<b><code>indexeddb.getAllKeys(store: IDBObjectStore, range: IDBKeyRange): Promise&lt;Array&lt;any&gt;&gt;</code></b><br>
761<b><code>indexeddb.queryFirst(store: IDBObjectStore, query: IDBKeyRange|null, direction: 'next'|'prev'|'nextunique'|'prevunique'): Promise&lt;any&gt;</code></b><br>
762<b><code>indexeddb.getLastKey(store: IDBObjectStore, range: IDBKeyRange?): Promise&lt;any&gt;</code></b><br>
763<b><code>indexeddb.getFirstKey(store: IDBObjectStore, range: IDBKeyRange?): Promise&lt;any&gt;</code></b><br>
764<b><code>indexeddb.getAllKeysValues(store: IDBObjectStore, range: IDBKeyRange): Promise&lt;Array&lt;KeyValuePair&gt;&gt;</code></b><br>
765<b><code>indexeddb.iterate(store: IDBObjectStore, keyrange: IDBKeyRange|null, f: function(any,any):void|boolean, direction: 'next'|'prev'|'nextunique'|'prevunique')</code></b><br>
766<dd><p>Iterate on keys and values</p></dd>
767<b><code>indexeddb.iterateKeys(store: IDBObjectStore, keyrange: IDBKeyRange|null, f: function(any):void|boolean, direction: 'next'|'prev'|'nextunique'|'prevunique')</code></b><br>
768<dd><p>Iterate on the keys (no values)</p></dd>
769<b><code>indexeddb.getStore(t: IDBTransaction, store: String)IDBObjectStore</code></b><br>
770<dd><p>Open store from transaction</p></dd>
771<b><code>indexeddb.createIDBKeyRangeBound(lower: any, upper: any, lowerOpen: boolean, upperOpen: boolean)</code></b><br>
772<b><code>indexeddb.createIDBKeyRangeUpperBound(upper: any, upperOpen: boolean)</code></b><br>
773<b><code>indexeddb.createIDBKeyRangeLowerBound(lower: any, lowerOpen: boolean)</code></b><br>
774</dl>
775</details>
776<details><summary><b>[lib0/isomorphic]</b> Isomorphic library exports from isomorphic.js.</summary>
777<pre>import * as isomorphic from 'lib0/isomorphic'</pre>
778<dl>
779</dl>
780</details>
781<details><summary><b>[lib0/iterator]</b> Utility module to create and manipulate Iterators.</summary>
782<pre>import * as iterator from 'lib0/iterator'</pre>
783<dl>
784<b><code>iterator.mapIterator(iterator: Iterator&lt;T&gt;, f: function(T):R): IterableIterator&lt;R&gt;</code></b><br>
785<b><code>iterator.createIterator(next: function():IteratorResult&lt;T&gt;): IterableIterator&lt;T&gt;</code></b><br>
786<b><code>iterator.iteratorFilter(iterator: Iterator&lt;T&gt;, filter: function(T):boolean)</code></b><br>
787<b><code>iterator.iteratorMap(iterator: Iterator&lt;T&gt;, fmap: function(T):M)</code></b><br>
788</dl>
789</details>
790<details><summary><b>[lib0/json]</b> JSON utility functions.</summary>
791<pre>import * as json from 'lib0/json'</pre>
792<dl>
793<b><code>json.stringify(object: any): string</code></b><br>
794<dd><p>Transform JavaScript object to JSON.</p></dd>
795<b><code>json.parse(json: string): any</code></b><br>
796<dd><p>Parse JSON object.</p></dd>
797</dl>
798</details>
799<details><summary><b>[lib0/list]</b> </summary>
800<pre>import * as list from 'lib0/list'</pre>
801<dl>
802<b><code>new e#ListNode()</code></b><br>
803<b><code>e#next: this|null</code></b><br>
804<b><code>e#prev: this|null</code></b><br>
805<b><code>new st()</code></b><br>
806<b><code>art: N | null</code></b><br>
807<b><code>d: N | null</code></b><br>
808<b><code>(): module:list.List&lt;N&gt;</code></b><br>
809<b><code>()</code></b><br>
810<b><code>(queue: module:list.List&lt;N&gt;)</code></b><br>
811<b><code>()</code></b><br>
812<b><code>(queue: module:list.List&lt;N&gt;, node: N)</code></b><br>
813<dd><p>Remove a single node from the queue. Only works with Queues that operate on Doubly-linked lists of nodes.</p></dd>
814<b><code>()</code></b><br>
815<b><code>ode</code></b><br>
816<b><code>ode()</code></b><br>
817<b><code>etween(queue: module:list.List&lt;N&gt;, left: N| null, right: N| null, node: N)</code></b><br>
818<b><code>etween()</code></b><br>
819<b><code>(queue: module:list.List&lt;N&gt;, node: N, newNode: N)</code></b><br>
820<dd><p>Remove a single node from the queue. Only works with Queues that operate on Doubly-linked lists of nodes.</p></dd>
821<b><code>()</code></b><br>
822<b><code>(queue: module:list.List&lt;N&gt;, n: N)</code></b><br>
823<b><code>()</code></b><br>
824<b><code>nt(queue: module:list.List&lt;N&gt;, n: N)</code></b><br>
825<b><code>nt()</code></b><br>
826<b><code>t(list: module:list.List&lt;N&gt;): N| null</code></b><br>
827<b><code>t()</code></b><br>
828<b><code>(list: module:list.List&lt;N&gt;): N| null</code></b><br>
829<b><code>()</code></b><br>
830<b><code>(list: module:list.List&lt;N&gt;, f: function(N):M): Array&lt;M&gt;</code></b><br>
831<b><code>()</code></b><br>
832<b><code>(list: module:list.List&lt;N&gt;)</code></b><br>
833<b><code>()</code></b><br>
834<b><code>(list: module:list.List&lt;N&gt;, f: function(N):M)</code></b><br>
835<b><code>()</code></b><br>
836</dl>
837</details>
838<details><summary><b>[lib0/logging]</b> Isomorphic logging module with support for colors!</summary>
839<pre>import * as logging from 'lib0/logging'</pre>
840<dl>
841<b><code>logging.BOLD</code></b><br>
842<b><code>logging.UNBOLD</code></b><br>
843<b><code>logging.BLUE</code></b><br>
844<b><code>logging.GREY</code></b><br>
845<b><code>logging.GREEN</code></b><br>
846<b><code>logging.RED</code></b><br>
847<b><code>logging.PURPLE</code></b><br>
848<b><code>logging.ORANGE</code></b><br>
849<b><code>logging.UNCOLOR</code></b><br>
850<b><code>logging.print(args: Array&lt;string|Symbol|Object|number&gt;)</code></b><br>
851<b><code>logging.warn(args: Array&lt;string|Symbol|Object|number&gt;)</code></b><br>
852<b><code>logging.printError(err: Error)</code></b><br>
853<b><code>logging.printImg(url: string, height: number)</code></b><br>
854<b><code>logging.printImgBase64(base64: string, height: number)</code></b><br>
855<b><code>logging.group(args: Array&lt;string|Symbol|Object|number&gt;)</code></b><br>
856<b><code>logging.groupCollapsed(args: Array&lt;string|Symbol|Object|number&gt;)</code></b><br>
857<b><code>logging.groupEnd</code></b><br>
858<b><code>logging.printDom(createNode: function():Node)</code></b><br>
859<b><code>logging.printCanvas(canvas: HTMLCanvasElement, height: number)</code></b><br>
860<b><code>logging.vconsoles</code></b><br>
861<b><code>new logging.VConsole(dom: Element)</code></b><br>
862<b><code>logging.VConsole#ccontainer: Element</code></b><br>
863<b><code>logging.VConsole#group(args: Array&lt;string|Symbol|Object|number&gt;, collapsed: boolean)</code></b><br>
864<b><code>logging.VConsole#groupCollapsed(args: Array&lt;string|Symbol|Object|number&gt;)</code></b><br>
865<b><code>logging.VConsole#groupEnd()</code></b><br>
866<b><code>logging.VConsole#print(args: Array&lt;string|Symbol|Object|number&gt;)</code></b><br>
867<b><code>logging.VConsole#printError(err: Error)</code></b><br>
868<b><code>logging.VConsole#printImg(url: string, height: number)</code></b><br>
869<b><code>logging.VConsole#printDom(node: Node)</code></b><br>
870<b><code>logging.VConsole#destroy()</code></b><br>
871<b><code>logging.createVConsole(dom: Element)</code></b><br>
872<b><code>logging.createModuleLogger(moduleName: string): function(...any):void</code></b><br>
873</dl>
874</details>
875<details><summary><b>[lib0/map]</b> Utility module to work with key-value stores.</summary>
876<pre>import * as map from 'lib0/map'</pre>
877<dl>
878<b><code>map.create(): Map&lt;any, any&gt;</code></b><br>
879<dd><p>Creates a new Map instance.</p></dd>
880<b><code>map.copy(m: Map&lt;X,Y&gt;): Map&lt;X,Y&gt;</code></b><br>
881<dd><p>Copy a Map object into a fresh Map object.</p></dd>
882<b><code>map.setIfUndefined(map: Map&lt;K, T&gt;, key: K, createT: function():T): T</code></b><br>
883<dd><p>Get map property. Create T if property is undefined and set T on map.</p>
884<pre class="prettyprint source lang-js"><code>const listeners = map.setIfUndefined(events, 'eventName', set.create)
885listeners.add(listener)
886</code></pre></dd>
887<b><code>map.map(m: Map&lt;K,V&gt;, f: function(V,K):R): Array&lt;R&gt;</code></b><br>
888<dd><p>Creates an Array and populates it with the content of all key-value pairs using the <code>f(value, key)</code> function.</p></dd>
889<b><code>map.any(m: Map&lt;K,V&gt;, f: function(V,K):boolean): boolean</code></b><br>
890<dd><p>Tests whether any key-value pairs pass the test implemented by <code>f(value, key)</code>.</p></dd>
891<b><code>map.all(m: Map&lt;K,V&gt;, f: function(V,K):boolean): boolean</code></b><br>
892<dd><p>Tests whether all key-value pairs pass the test implemented by <code>f(value, key)</code>.</p></dd>
893</dl>
894</details>
895<details><summary><b>[lib0/math]</b> Common Math expressions.</summary>
896<pre>import * as math from 'lib0/math'</pre>
897<dl>
898<b><code>math.floor</code></b><br>
899<b><code>math.ceil</code></b><br>
900<b><code>math.abs</code></b><br>
901<b><code>math.imul</code></b><br>
902<b><code>math.round</code></b><br>
903<b><code>math.log10</code></b><br>
904<b><code>math.log2</code></b><br>
905<b><code>math.log</code></b><br>
906<b><code>math.sqrt</code></b><br>
907<b><code>math.add(a: number, b: number): number</code></b><br>
908<b><code>math.min(a: number, b: number): number</code></b><br>
909<b><code>math.max(a: number, b: number): number</code></b><br>
910<b><code>math.isNaN</code></b><br>
911<b><code>math.pow</code></b><br>
912<b><code>math.exp10(exp: number): number</code></b><br>
913<dd><p>Base 10 exponential function. Returns the value of 10 raised to the power of pow.</p></dd>
914<b><code>math.sign</code></b><br>
915<b><code>math.isNegativeZero(n: number): boolean</code></b><br>
916</dl>
917</details>
918<details><summary><b>[lib0/metric]</b> Utility module to convert metric values.</summary>
919<pre>import * as metric from 'lib0/metric'</pre>
920<dl>
921<b><code>metric.yotta</code></b><br>
922<b><code>metric.zetta</code></b><br>
923<b><code>metric.exa</code></b><br>
924<b><code>metric.peta</code></b><br>
925<b><code>metric.tera</code></b><br>
926<b><code>metric.giga</code></b><br>
927<b><code>metric.mega</code></b><br>
928<b><code>metric.kilo</code></b><br>
929<b><code>metric.hecto</code></b><br>
930<b><code>metric.deca</code></b><br>
931<b><code>metric.deci</code></b><br>
932<b><code>metric.centi</code></b><br>
933<b><code>metric.milli</code></b><br>
934<b><code>metric.micro</code></b><br>
935<b><code>metric.nano</code></b><br>
936<b><code>metric.pico</code></b><br>
937<b><code>metric.femto</code></b><br>
938<b><code>metric.atto</code></b><br>
939<b><code>metric.zepto</code></b><br>
940<b><code>metric.yocto</code></b><br>
941<b><code>metric.prefix(n: number, baseMultiplier: number): {n:number,prefix:string}</code></b><br>
942<dd><p>Calculate the metric prefix for a number. Assumes E.g. <code>prefix(1000) = { n: 1, prefix: 'k' }</code></p></dd>
943</dl>
944</details>
945<details><summary><b>[lib0/mutex]</b> Mutual exclude for JavaScript.</summary>
946<pre>import * as mutex from 'lib0/mutex'</pre>
947<dl>
948<b><code>mutex.createMutex(): mutex</code></b><br>
949<dd><p>Creates a mutual exclude function with the following property:</p>
950<pre class="prettyprint source lang-js"><code>const mutex = createMutex()
951mutex(() => {
952 // This function is immediately executed
953 mutex(() => {
954 // This function is not executed, as the mutex is already active.
955 })
956})
957</code></pre></dd>
958</dl>
959</details>
960<details><summary><b>[lib0/number]</b> </summary>
961<pre>import * as number from 'lib0/number'</pre>
962<dl>
963<b><code>number.MAX_SAFE_INTEGER</code></b><br>
964<b><code>number.MIN_SAFE_INTEGER</code></b><br>
965<b><code>number.LOWEST_INT32</code></b><br>
966<b><code>number.HIGHEST_INT32: number</code></b><br>
967<b><code>number.isInteger</code></b><br>
968<b><code>number.isNaN</code></b><br>
969<b><code>number.parseInt</code></b><br>
970</dl>
971</details>
972<details><summary><b>[lib0/object]</b> Utility functions for working with EcmaScript objects.</summary>
973<pre>import * as object from 'lib0/object'</pre>
974<dl>
975<b><code>object.create(): Object&lt;string,any&gt;</code></b><br>
976<b><code>object.assign</code></b><br>
977<dd><p>Object.assign</p></dd>
978<b><code>object.keys(obj: Object&lt;string,any&gt;)</code></b><br>
979<b><code>object.forEach(obj: Object&lt;string,any&gt;, f: function(any,string):any)</code></b><br>
980<b><code>object.map(obj: Object&lt;string,any&gt;, f: function(any,string):R): Array&lt;R&gt;</code></b><br>
981<b><code>object.length(obj: Object&lt;string,any&gt;): number</code></b><br>
982<b><code>object.some(obj: Object&lt;string,any&gt;, f: function(any,string):boolean): boolean</code></b><br>
983<b><code>object.every(obj: Object&lt;string,any&gt;, f: function(any,string):boolean): boolean</code></b><br>
984<b><code>object.hasProperty(obj: any, key: string|symbol): boolean</code></b><br>
985<dd><p>Calls <code>Object.prototype.hasOwnProperty</code>.</p></dd>
986<b><code>object.equalFlat(a: Object&lt;string,any&gt;, b: Object&lt;string,any&gt;): boolean</code></b><br>
987</dl>
988</details>
989<details><summary><b>[lib0/observable]</b> Observable class prototype.</summary>
990<pre>import * as observable from 'lib0/observable'</pre>
991<dl>
992<b><code>new observable.Observable()</code></b><br>
993<dd><p>Handles named events.</p></dd>
994<b><code>observable.Observable#on(name: N, f: function)</code></b><br>
995<b><code>observable.Observable#once(name: N, f: function)</code></b><br>
996<b><code>observable.Observable#off(name: N, f: function)</code></b><br>
997<b><code>observable.Observable#emit(name: N, args: Array&lt;any&gt;)</code></b><br>
998<dd><p>Emit a named event. All registered event listeners that listen to the
999specified name will receive the event.</p></dd>
1000<b><code>observable.Observable#destroy()</code></b><br>
1001<b><code>websocket.WebsocketClient#on(name: N, f: function)</code></b><br>
1002<b><code>websocket.WebsocketClient#once(name: N, f: function)</code></b><br>
1003<b><code>websocket.WebsocketClient#off(name: N, f: function)</code></b><br>
1004<b><code>websocket.WebsocketClient#emit(name: N, args: Array&lt;any&gt;)</code></b><br>
1005<dd><p>Emit a named event. All registered event listeners that listen to the
1006specified name will receive the event.</p></dd>
1007</dl>
1008</details>
1009<details><summary><b>[lib0/pair]</b> Working with value pairs.</summary>
1010<pre>import * as pair from 'lib0/pair'</pre>
1011<dl>
1012<b><code>new pair.Pair(left: L, right: R)</code></b><br>
1013<b><code>pair.create(left: L, right: R): module:pair.Pair&lt;L,R&gt;</code></b><br>
1014<b><code>pair.createReversed(right: R, left: L): module:pair.Pair&lt;L,R&gt;</code></b><br>
1015<b><code>pair.forEach(arr: Array&lt;module:pair.Pair&lt;L,R&gt;&gt;, f: function(L, R):any)</code></b><br>
1016<b><code>pair.map(arr: Array&lt;module:pair.Pair&lt;L,R&gt;&gt;, f: function(L, R):X): Array&lt;X&gt;</code></b><br>
1017</dl>
1018</details>
1019<details><summary><b>[lib0/prng]</b> Fast Pseudo Random Number Generators.</summary>
1020<pre>import * as prng from 'lib0/prng'</pre>
1021
1022<p>Given a seed a PRNG generates a sequence of numbers that cannot be reasonably predicted.
1023Two PRNGs must generate the same random sequence of numbers if given the same seed.</p>
1024<dl>
1025<b><code>prng.DefaultPRNG</code></b><br>
1026<b><code>prng.create(seed: number): module:prng~PRNG</code></b><br>
1027<dd><p>Create a Xoroshiro128plus Pseudo-Random-Number-Generator.
1028This is the fastest full-period generator passing BigCrush without systematic failures.
1029But there are more PRNGs available in ./PRNG/.</p></dd>
1030<b><code>prng.bool(gen: module:prng~PRNG): Boolean</code></b><br>
1031<dd><p>Generates a single random bool.</p></dd>
1032<b><code>prng.int53(gen: module:prng~PRNG, min: Number, max: Number): Number</code></b><br>
1033<dd><p>Generates a random integer with 53 bit resolution.</p></dd>
1034<b><code>prng.uint53(gen: module:prng~PRNG, min: Number, max: Number): Number</code></b><br>
1035<dd><p>Generates a random integer with 53 bit resolution.</p></dd>
1036<b><code>prng.int32(gen: module:prng~PRNG, min: Number, max: Number): Number</code></b><br>
1037<dd><p>Generates a random integer with 32 bit resolution.</p></dd>
1038<b><code>prng.uint32(gen: module:prng~PRNG, min: Number, max: Number): Number</code></b><br>
1039<dd><p>Generates a random integer with 53 bit resolution.</p></dd>
1040<b><code>prng.int31(gen: module:prng~PRNG, min: Number, max: Number): Number</code></b><br>
1041<b><code>prng.real53(gen: module:prng~PRNG): Number</code></b><br>
1042<dd><p>Generates a random real on [0, 1) with 53 bit resolution.</p></dd>
1043<b><code>prng.char(gen: module:prng~PRNG): string</code></b><br>
1044<dd><p>Generates a random character from char code 32 - 126. I.e. Characters, Numbers, special characters, and Space:</p></dd>
1045<b><code>prng.letter(gen: module:prng~PRNG): string</code></b><br>
1046<b><code>prng.word(gen: module:prng~PRNG, minLen: number, maxLen: number): string</code></b><br>
1047<b><code>prng.utf16Rune(gen: module:prng~PRNG): string</code></b><br>
1048<dd><p>TODO: this function produces invalid runes. Does not cover all of utf16!!</p></dd>
1049<b><code>prng.utf16String(gen: module:prng~PRNG, maxlen: number)</code></b><br>
1050<b><code>prng.oneOf(gen: module:prng~PRNG, array: Array&lt;T&gt;): T</code></b><br>
1051<dd><p>Returns one element of a given array.</p></dd>
1052<b><code>prng.uint8Array(gen: module:prng~PRNG, len: number): Uint8Array</code></b><br>
1053<b><code>prng.uint16Array(gen: module:prng~PRNG, len: number): Uint16Array</code></b><br>
1054<b><code>prng.uint32Array(gen: module:prng~PRNG, len: number): Uint32Array</code></b><br>
1055</dl>
1056</details>
1057<details><summary><b>[lib0/promise]</b> Utility helpers to work with promises.</summary>
1058<pre>import * as promise from 'lib0/promise'</pre>
1059<dl>
1060<b><code>promise.create(f: function(PromiseResolve&lt;T&gt;,function(Error):void):any): Promise&lt;T&gt;</code></b><br>
1061<b><code>promise.createEmpty(f: function(function():void,function(Error):void):void): Promise&lt;void&gt;</code></b><br>
1062<b><code>promise.all(arrp: Array&lt;Promise&lt;T&gt;&gt;): Promise&lt;Array&lt;T&gt;&gt;</code></b><br>
1063<dd><p><code>Promise.all</code> wait for all promises in the array to resolve and return the result</p></dd>
1064<b><code>promise.reject(reason: Error): Promise&lt;never&gt;</code></b><br>
1065<b><code>promise.resolve(res: T|void): Promise&lt;T|void&gt;</code></b><br>
1066<b><code>promise.resolveWith(res: T): Promise&lt;T&gt;</code></b><br>
1067<b><code>promise.until(timeout: number, check: function():boolean, intervalResolution: number): Promise&lt;void&gt;</code></b><br>
1068<b><code>promise.wait(timeout: number): Promise&lt;undefined&gt;</code></b><br>
1069<b><code>promise.isPromise(p: any): boolean</code></b><br>
1070<dd><p>Checks if an object is a promise using ducktyping.</p>
1071<p>Promises are often polyfilled, so it makes sense to add some additional guarantees if the user of this
1072library has some insane environment where global Promise objects are overwritten.</p></dd>
1073</dl>
1074</details>
1075<details><summary><b>[lib0/queue]</b> </summary>
1076<pre>import * as queue from 'lib0/queue'</pre>
1077<dl>
1078<b><code>new de#QueueNode()</code></b><br>
1079<b><code>de#next: module:queue.QueueNode|null</code></b><br>
1080<b><code>new ueue()</code></b><br>
1081<b><code>tart: module:queue.QueueNode | null</code></b><br>
1082<b><code>nd: module:queue.QueueNode | null</code></b><br>
1083<b><code>(): module:queue.Queue</code></b><br>
1084<b><code>()</code></b><br>
1085<b><code>(queue: module:queue.Queue)</code></b><br>
1086<b><code>()</code></b><br>
1087<b><code>(queue: module:queue.Queue, n: module:queue.QueueNode)</code></b><br>
1088<b><code>()</code></b><br>
1089<b><code>(queue: module:queue.Queue): module:queue.QueueNode | null</code></b><br>
1090<b><code>()</code></b><br>
1091</dl>
1092</details>
1093<details><summary><b>[lib0/random]</b> Isomorphic module for true random numbers / buffers / uuids.</summary>
1094<pre>import * as random from 'lib0/random'</pre>
1095
1096<p>Attention: falls back to Math.random if the browser does not support crypto.</p>
1097<dl>
1098<b><code>random.rand</code></b><br>
1099<b><code>random.uint32</code></b><br>
1100<b><code>random.uint53</code></b><br>
1101<b><code>random.oneOf(arr: Array&lt;T&gt;): T</code></b><br>
1102<b><code>random.uuidv4</code></b><br>
1103</dl>
1104</details>
1105<details><summary><b>[lib0/set]</b> Utility module to work with sets.</summary>
1106<pre>import * as set from 'lib0/set'</pre>
1107<dl>
1108<b><code>set.create</code></b><br>
1109<b><code>set.toArray(set: Set&lt;T&gt;): Array&lt;T&gt;</code></b><br>
1110<b><code>set.first(set: Set&lt;T&gt;): T</code></b><br>
1111<b><code>set.from(entries: Iterable&lt;T&gt;): Set&lt;T&gt;</code></b><br>
1112</dl>
1113</details>
1114<details><summary><b>[lib0/sort]</b> Efficient sort implementations.</summary>
1115<pre>import * as sort from 'lib0/sort'</pre>
1116
1117<p>Note: These sort implementations were created to compare different sorting algorithms in JavaScript.
1118Don't use them if you don't know what you are doing. Native Array.sort is almost always a better choice.</p>
1119<dl>
1120<b><code>sort.insertionSort(arr: Array&lt;T&gt;, compare: function(T,T):number): void</code></b><br>
1121<b><code>sort.quicksort(arr: Array&lt;T&gt;, compare: function(T,T):number): void</code></b><br>
1122<dd><p>This algorithm beats Array.prototype.sort in Chrome only with arrays with 10 million entries.
1123In most cases [].sort will do just fine. Make sure to performance test your use-case before you
1124integrate this algorithm.</p>
1125<p>Note that Chrome's sort is now a stable algorithm (Timsort). Quicksort is not stable.</p></dd>
1126</dl>
1127</details>
1128<details><summary><b>[lib0/statistics]</b> Utility helpers for generating statistics.</summary>
1129<pre>import * as statistics from 'lib0/statistics'</pre>
1130<dl>
1131<b><code>statistics.median(arr: Array&lt;number&gt;): number</code></b><br>
1132<b><code>statistics.average(arr: Array&lt;number&gt;): number</code></b><br>
1133</dl>
1134</details>
1135<details><summary><b>[lib0/storage]</b> Isomorphic variable storage.</summary>
1136<pre>import * as storage from 'lib0/storage'</pre>
1137
1138<p>Uses LocalStorage in the browser and falls back to in-memory storage.</p>
1139<dl>
1140<b><code>storage.varStorage</code></b><br>
1141<dd><p>This is basically localStorage in browser, or a polyfill in nodejs</p></dd>
1142<b><code>storage.onChange(eventHandler: function({ key: string, newValue: string, oldValue: string }): void)</code></b><br>
1143<dd><p>A polyfill for <code>addEventListener('storage', event =&gt; {..})</code> that does nothing if the polyfill is being used.</p></dd>
1144</dl>
1145</details>
1146<details><summary><b>[lib0/string]</b> Utility module to work with strings.</summary>
1147<pre>import * as string from 'lib0/string'</pre>
1148<dl>
1149<b><code>string.fromCharCode</code></b><br>
1150<b><code>string.fromCodePoint</code></b><br>
1151<b><code>string.trimLeft(s: string): string</code></b><br>
1152<b><code>string.fromCamelCase(s: string, separator: string): string</code></b><br>
1153<b><code>string.utf8ByteLength(str: string): number</code></b><br>
1154<dd><p>Compute the utf8ByteLength</p></dd>
1155<b><code>string.utf8TextEncoder</code></b><br>
1156<b><code>string.encodeUtf8</code></b><br>
1157<b><code>string.decodeUtf8</code></b><br>
1158<b><code>string.splice(str: string, index: number, remove: number, insert: string)</code></b><br>
1159</dl>
1160</details>
1161<details><summary><b>[lib0/symbol]</b> Utility module to work with EcmaScript Symbols.</summary>
1162<pre>import * as symbol from 'lib0/symbol'</pre>
1163<dl>
1164<b><code>symbol.create(): Symbol</code></b><br>
1165<dd><p>Return fresh symbol.</p></dd>
1166<b><code>symbol.isSymbol(s: any): boolean</code></b><br>
1167</dl>
1168</details>
1169<details><summary><b>[lib0/testing]</b> Testing framework with support for generating tests.</summary>
1170<pre>import * as testing from 'lib0/testing'</pre>
1171
1172<pre class="prettyprint source lang-js"><code>// test.js template for creating a test executable
1173import { runTests } from 'lib0/testing'
1174import * as log from 'lib0/logging'
1175import * as mod1 from './mod1.test.js'
1176import * as mod2 from './mod2.test.js'
1177import { isBrowser, isNode } from 'lib0/environment.js'
1178
1179if (isBrowser) {
1180 // optional: if this is ran in the browser, attach a virtual console to the dom
1181 log.createVConsole(document.body)
1182}
1183
1184runTests({
1185 mod1,
1186 mod2,
1187}).then(success => {
1188 if (isNode) {
1189 process.exit(success ? 0 : 1)
1190 }
1191})
1192</code></pre>
1193<pre class="prettyprint source lang-js"><code>// mod1.test.js
1194/**
1195 * runTests automatically tests all exported functions that start with &quot;test&quot;.
1196 * The name of the function should be in camelCase and is used for the logging output.
1197 *
1198 * @param {t.TestCase} tc
1199 *\/
1200export const testMyFirstTest = tc => {
1201 t.compare({ a: 4 }, { a: 4 }, 'objects are equal')
1202}
1203</code></pre>
1204<p>Now you can simply run <code>node test.js</code> to run your test or run test.js in the browser.</p>
1205<dl>
1206<b><code>testing.extensive</code></b><br>
1207<b><code>testing.envSeed</code></b><br>
1208<b><code>new testing.TestCase(moduleName: string, testName: string)</code></b><br>
1209<b><code>testing.TestCase#moduleName: string</code></b><br>
1210<b><code>testing.TestCase#testName: string</code></b><br>
1211<b><code>testing.TestCase#resetSeed()</code></b><br>
1212<b><code>testing.TestCase#prng: prng.PRNG</code></b><br>
1213<dd><p>A PRNG for this test case. Use only this PRNG for randomness to make the test case reproducible.</p></dd>
1214<b><code>testing.repetitionTime</code></b><br>
1215<b><code>testing.run(moduleName: string, name: string, f: function(module:testing.TestCase):void|Promise&lt;any&gt;, i: number, numberOfTests: number)</code></b><br>
1216<b><code>testing.describe(description: string, info: string)</code></b><br>
1217<dd><p>Describe what you are currently testing. The message will be logged.</p>
1218<pre class="prettyprint source lang-js"><code>export const testMyFirstTest = tc => {
1219 t.describe('crunching numbers', 'already crunched 4 numbers!') // the optional second argument can describe the state.
1220}
1221</code></pre></dd>
1222<b><code>testing.info(info: string)</code></b><br>
1223<dd><p>Describe the state of the current computation.</p>
1224<pre class="prettyprint source lang-js"><code>export const testMyFirstTest = tc => {
1225 t.info(already crunched 4 numbers!') // the optional second argument can describe the state.
1226}
1227</code></pre></dd>
1228<b><code>testing.printDom</code></b><br>
1229<b><code>testing.printCanvas</code></b><br>
1230<b><code>testing.group(description: string, f: function(void):void)</code></b><br>
1231<dd><p>Group outputs in a collapsible category.</p>
1232<pre class="prettyprint source lang-js"><code>export const testMyFirstTest = tc => {
1233 t.group('subtest 1', () => {
1234 t.describe('this message is part of a collapsible section')
1235 })
1236 await t.groupAsync('subtest async 2', async () => {
1237 await someaction()
1238 t.describe('this message is part of a collapsible section')
1239 })
1240}
1241</code></pre></dd>
1242<b><code>testing.groupAsync(description: string, f: function(void):Promise&lt;any&gt;)</code></b><br>
1243<dd><p>Group outputs in a collapsible category.</p>
1244<pre class="prettyprint source lang-js"><code>export const testMyFirstTest = async tc => {
1245 t.group('subtest 1', () => {
1246 t.describe('this message is part of a collapsible section')
1247 })
1248 await t.groupAsync('subtest async 2', async () => {
1249 await someaction()
1250 t.describe('this message is part of a collapsible section')
1251 })
1252}
1253</code></pre></dd>
1254<b><code>testing.measureTime(message: string, f: function():void): number</code></b><br>
1255<dd><p>Measure the time that it takes to calculate something.</p>
1256<pre class="prettyprint source lang-js"><code>export const testMyFirstTest = async tc => {
1257 t.measureTime('measurement', () => {
1258 heavyCalculation()
1259 })
1260 await t.groupAsync('async measurement', async () => {
1261 await heavyAsyncCalculation()
1262 })
1263}
1264</code></pre></dd>
1265<b><code>testing.measureTimeAsync(message: string, f: function():Promise&lt;any&gt;): Promise&lt;number&gt;</code></b><br>
1266<dd><p>Measure the time that it takes to calculate something.</p>
1267<pre class="prettyprint source lang-js"><code>export const testMyFirstTest = async tc => {
1268 t.measureTimeAsync('measurement', async () => {
1269 await heavyCalculation()
1270 })
1271 await t.groupAsync('async measurement', async () => {
1272 await heavyAsyncCalculation()
1273 })
1274}
1275</code></pre></dd>
1276<b><code>testing.compareArrays(as: Array&lt;T&gt;, bs: Array&lt;T&gt;, m: string): boolean</code></b><br>
1277<b><code>testing.compareStrings(a: string, b: string, m: string)</code></b><br>
1278<b><code>testing.compareObjects(a: Object&lt;K,V&gt;, b: Object&lt;K,V&gt;, m: string)</code></b><br>
1279<b><code>testing.compare(a: T, b: T, message: string?, customCompare: function(any,T,T,string,any):boolean)</code></b><br>
1280<b><code>testing.assert(condition: boolean, message: string?)</code></b><br>
1281<b><code>testing.fails(f: function():void)</code></b><br>
1282<b><code>testing.runTests(tests: Object&lt;string, Object&lt;string, function(module:testing.TestCase):void|Promise&lt;any&gt;&gt;&gt;)</code></b><br>
1283<b><code>testing.fail(reason: string)</code></b><br>
1284<b><code>testing.skip(cond: boolean)</code></b><br>
1285</dl>
1286</details>
1287<details><summary><b>[lib0/time]</b> Utility module to work with time.</summary>
1288<pre>import * as time from 'lib0/time'</pre>
1289<dl>
1290<b><code>time.getDate(): Date</code></b><br>
1291<dd><p>Return current time.</p></dd>
1292<b><code>time.getUnixTime(): number</code></b><br>
1293<dd><p>Return current unix time.</p></dd>
1294<b><code>time.humanizeDuration(d: number): string</code></b><br>
1295<dd><p>Transform time (in ms) to a human readable format. E.g. 1100 =&gt; 1.1s. 60s =&gt; 1min. .001 =&gt; 10μs.</p></dd>
1296</dl>
1297</details>
1298<details><summary><b>[lib0/tree]</b> Red-black-tree implementation.</summary>
1299<pre>import * as tree from 'lib0/tree'</pre>
1300<dl>
1301<b><code>new tree.Tree()</code></b><br>
1302<dd><p>This is a Red Black Tree implementation</p></dd>
1303<b><code>tree.Tree#findNext(id: K)</code></b><br>
1304<b><code>tree.Tree#findPrev(id: K)</code></b><br>
1305<b><code>tree.Tree#findNodeWithLowerBound(from: K)</code></b><br>
1306<b><code>tree.Tree#findNodeWithUpperBound(to: K)</code></b><br>
1307<b><code>tree.Tree#findSmallestNode(): V</code></b><br>
1308<b><code>tree.Tree#findWithLowerBound(from: K): V</code></b><br>
1309<b><code>tree.Tree#findWithUpperBound(to: K): V</code></b><br>
1310<b><code>tree.Tree#iterate(from: K, from: K, f: K)</code></b><br>
1311<b><code>tree.Tree#find(id: K): V|null</code></b><br>
1312<b><code>tree.Tree#findNode(id: K): module:tree~N&lt;V&gt;|null</code></b><br>
1313<b><code>tree.Tree#delete(id: K)</code></b><br>
1314<b><code>tree.Tree#put()</code></b><br>
1315</dl>
1316</details>
1317<details><summary><b>[lib0/url]</b> Utility module to work with urls.</summary>
1318<pre>import * as url from 'lib0/url'</pre>
1319<dl>
1320<b><code>url.decodeQueryParams(url: string): Object&lt;string,string&gt;</code></b><br>
1321<dd><p>Parse query parameters from an url.</p></dd>
1322<b><code>url.encodeQueryParams(params: Object&lt;string,string&gt;): string</code></b><br>
1323</dl>
1324</details>
1325<details><summary><b>[lib0/websocket]</b> Tiny websocket connection handler.</summary>
1326<pre>import * as websocket from 'lib0/websocket'</pre>
1327
1328<p>Implements exponential backoff reconnects, ping/pong, and a nice event system using [lib0/observable].</p>
1329<dl>
1330<b><code>new websocket.WebsocketClient(url: string, opts: object, opts.binaryType: 'arraybuffer' | 'blob' | null)</code></b><br>
1331<b><code>websocket.WebsocketClient#ws: WebSocket?</code></b><br>
1332<b><code>websocket.WebsocketClient#shouldConnect: boolean</code></b><br>
1333<dd><p>Whether to connect to other peers or not</p></dd>
1334<b><code>websocket.WebsocketClient#send(message: any)</code></b><br>
1335<b><code>websocket.WebsocketClient#destroy()</code></b><br>
1336<b><code>websocket.WebsocketClient#disconnect()</code></b><br>
1337<b><code>websocket.WebsocketClient#connect()</code></b><br>
1338</dl>
1339</details>
1340
1341### License
1342
1343[The MIT License](./LICENSE) © Kevin Jahns