@luvies/lazy
Version:
A linq-like lazy iteration module that aims to support deno, node & browser
376 lines (359 loc) • 47 kB
HTML
<html class="default no-js">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>@luvies/lazy</title>
<meta name="description" content="Documentation for @luvies/lazy">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="assets/css/main.css">
<script async src="assets/js/search.js" id="search-script"></script>
</head>
<body>
<header>
<div class="tsd-page-toolbar">
<div class="container">
<div class="table-wrap">
<div class="table-cell" id="tsd-search" data-index="assets/js/search.json" data-base=".">
<div class="field">
<label for="tsd-search-field" class="tsd-widget search no-caption">Search</label>
<input id="tsd-search-field" type="text" />
</div>
<ul class="results">
<li class="state loading">Preparing search index...</li>
<li class="state failure">The search index is not available</li>
</ul>
<a href="index.html" class="title">@luvies/lazy</a>
</div>
<div class="table-cell" id="tsd-widgets">
<div id="tsd-filter">
<a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a>
<div class="tsd-filter-group">
<div class="tsd-select" id="tsd-filter-visibility">
<span class="tsd-select-label">All</span>
<ul class="tsd-select-list">
<li data-value="public">Public</li>
<li data-value="protected">Public/Protected</li>
<li data-value="private" class="selected">All</li>
</ul>
</div>
<input type="checkbox" id="tsd-filter-inherited" checked />
<label class="tsd-widget" for="tsd-filter-inherited">Inherited</label>
<input type="checkbox" id="tsd-filter-externals" checked />
<label class="tsd-widget" for="tsd-filter-externals">Externals</label>
</div>
</div>
<a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a>
</div>
</div>
</div>
</div>
<div class="tsd-page-title">
<div class="container">
<h1>Project @luvies/lazy</h1>
</div>
</div>
</header>
<div class="container container-main">
<div class="row">
<div class="col-8 col-content">
<div class="tsd-panel tsd-typography">
<a href="#lazy-iteration" id="lazy-iteration" style="color: inherit; text-decoration: none;">
<h1>Lazy Iteration</h1>
</a>
<p><a href="https://travis-ci.com/luvies/lazy"><img src="https://travis-ci.com/luvies/lazy.svg?branch=master" alt="Build Status"></a> <img src="https://github.com/luvies/lazy/workflows/Node%2FDeno%20CI/badge.svg" alt="Github Build Status"> <a href="https://badge.fury.io/js/%40luvies%2Flazy"><img src="https://badge.fury.io/js/%40luvies%2Flazy.svg" alt="npm version"></a></p>
<p>This module is meant to provide memory-efficient lazy-evaluation iteration for iterable objects. The aim of this project is to support deno, node and browser, and support all native JavaScript systems for iteration (for-of, for-await-of, etc).</p>
<a href="#contents" id="contents" style="color: inherit; text-decoration: none;">
<h2>Contents</h2>
</a>
<ul>
<li><a href="#installation">Installation</a><ul>
<li><a href="#deno">Deno</a></li>
<li><a href="#node">Node</a></li>
</ul>
</li>
<li><a href="#overview">Overview</a></li>
<li><a href="#examples">Examples</a></li>
<li><a href="#interop-with-native">Introp with native</a></li>
<li><a href="#api">API</a><ul>
<li><a href="#promises">Promises</a></li>
<li><a href="#no-additional-unexpected-iteration">No additional unexpected iteration</a></li>
<li><a href="#custom-implementations">Custom implementations</a></li>
<li><a href="#compatibility">Compatibility</a></li>
<li><a href="#shorthand-usage">Shorthand usage</a></li>
</ul>
</li>
<li><a href="#setting-up-this-project">Setting up this project</a></li>
<li><a href="#footnotes">Footnotes</a></li>
</ul>
<a href="#installation" id="installation" style="color: inherit; text-decoration: none;">
<h2>Installation</h2>
</a>
<a href="#deno" id="deno" style="color: inherit; text-decoration: none;">
<h3>Deno</h3>
</a>
<p>Use the following import:</p>
<pre><code class="language-ts"><span style="color: #AF00DB">import</span><span style="color: #000000"> { </span><span style="color: #001080">Lazy</span><span style="color: #000000"> } </span><span style="color: #AF00DB">from</span><span style="color: #000000"> </span><span style="color: #A31515">'https://deno.land/x/lazy@v{version}/mod.ts'</span><span style="color: #000000">;</span>
</code></pre>
<p>Make sure the <code>@v{version}</code> tag is the correct one you want. I'd recommend against master, as it could change without notice & might be broken (although I will try not to break it).</p>
<a href="#node" id="node" style="color: inherit; text-decoration: none;">
<h3>Node</h3>
</a>
<p>The packge can be found here: <a href="https://www.npmjs.com/package/@luvies/lazy">https://www.npmjs.com/package/@luvies/lazy</a>.</p>
<p>Install via</p>
<pre><code><span style="color: #001080">yarn</span><span style="color: #000000"> </span><span style="color: #001080">add</span><span style="color: #000000"> @</span><span style="color: #001080">luvies</span><span style="color: #000000">/</span><span style="color: #001080">lazy</span>
</code></pre>
<p>or</p>
<pre><code><span style="color: #001080">npm</span><span style="color: #000000"> </span><span style="color: #001080">install</span><span style="color: #000000"> @</span><span style="color: #001080">luvies</span><span style="color: #000000">/</span><span style="color: #001080">lazy</span>
</code></pre>
<p>Import using</p>
<pre><code class="language-ts"><span style="color: #AF00DB">import</span><span style="color: #000000"> { </span><span style="color: #001080">Lazy</span><span style="color: #000000"> } </span><span style="color: #AF00DB">from</span><span style="color: #000000"> </span><span style="color: #A31515">'@luvies/lazy'</span><span style="color: #000000">;</span>
</code></pre>
<p>or</p>
<pre><code class="language-js"><span style="color: #0000FF">const</span><span style="color: #000000"> { </span><span style="color: #0070C1">Lazy</span><span style="color: #000000"> } = </span><span style="color: #795E26">require</span><span style="color: #000000">(</span><span style="color: #A31515">'@luvies/lazy'</span><span style="color: #000000">);</span>
</code></pre>
<a href="#overview" id="overview" style="color: inherit; text-decoration: none;">
<h2>Overview</h2>
</a>
<p>At a base level, this module provides the following exports:</p>
<pre><code class="language-ts"><span style="color: #0000FF">abstract</span><span style="color: #000000"> </span><span style="color: #0000FF">class</span><span style="color: #000000"> </span><span style="color: #267F99">Lazy</span><span style="color: #000000"><</span><span style="color: #267F99">TElement</span><span style="color: #000000">> {...}</span>
<span style="color: #008000">// These are provided to allow direct imports, but are just aliases over the static class methods.</span>
<span style="color: #0000FF">function</span><span style="color: #000000"> </span><span style="color: #795E26">from</span><span style="color: #000000"><</span><span style="color: #267F99">TElement</span><span style="color: #000000">>(</span><span style="color: #001080">iterable</span><span style="color: #000000">: </span><span style="color: #267F99">Iterable</span><span style="color: #000000"><</span><span style="color: #267F99">TElement</span><span style="color: #000000">>): </span><span style="color: #267F99">Lazy</span><span style="color: #000000"><</span><span style="color: #267F99">TElement</span><span style="color: #000000">>;</span>
<span style="color: #0000FF">function</span><span style="color: #000000"> </span><span style="color: #795E26">empty</span><span style="color: #000000"><</span><span style="color: #267F99">TElement</span><span style="color: #000000">>(): </span><span style="color: #267F99">Lazy</span><span style="color: #000000"><</span><span style="color: #267F99">TElement</span><span style="color: #000000">>;</span>
<span style="color: #0000FF">function</span><span style="color: #000000"> </span><span style="color: #795E26">range</span><span style="color: #000000">(</span><span style="color: #001080">start</span><span style="color: #000000">: </span><span style="color: #267F99">number</span><span style="color: #000000">, </span><span style="color: #001080">end</span><span style="color: #000000">?: </span><span style="color: #267F99">number</span><span style="color: #000000">): </span><span style="color: #267F99">Lazy</span><span style="color: #000000"><</span><span style="color: #267F99">number</span><span style="color: #000000">>;</span>
<span style="color: #0000FF">function</span><span style="color: #000000"> </span><span style="color: #795E26">repeat</span><span style="color: #000000"><</span><span style="color: #267F99">TElement</span><span style="color: #000000">>(</span><span style="color: #001080">element</span><span style="color: #000000">: </span><span style="color: #267F99">TElement</span><span style="color: #000000">, </span><span style="color: #001080">count</span><span style="color: #000000">?: </span><span style="color: #267F99">number</span><span style="color: #000000">): </span><span style="color: #267F99">Lazy</span><span style="color: #000000"><</span><span style="color: #267F99">TElement</span><span style="color: #000000">>;</span>
</code></pre>
<p>The <code>Lazy</code> class is the root of the module, all things come from it and are derived off it. To start using it, do something like the following:</p>
<pre><code class="language-ts"><span style="color: #008000">// Static method import.</span>
<span style="color: #AF00DB">import</span><span style="color: #000000"> { </span><span style="color: #001080">Lazy</span><span style="color: #000000"> } </span><span style="color: #AF00DB">from</span><span style="color: #000000"> </span><span style="color: #A31515">'https://deno.land/x/lazy@v{version}/mod.ts'</span><span style="color: #000000">;</span>
<span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">iterable</span><span style="color: #000000"> = </span><span style="color: #001080">Lazy</span><span style="color: #000000">.</span><span style="color: #795E26">from</span><span style="color: #000000">([</span><span style="color: #098658">1</span><span style="color: #000000">, </span><span style="color: #098658">2</span><span style="color: #000000">, </span><span style="color: #098658">3</span><span style="color: #000000">, </span><span style="color: #098658">4</span><span style="color: #000000">, </span><span style="color: #098658">5</span><span style="color: #000000">]);</span>
<span style="color: #008000">// Direct function import.</span>
<span style="color: #AF00DB">import</span><span style="color: #000000"> { </span><span style="color: #001080">from</span><span style="color: #000000"> } </span><span style="color: #AF00DB">from</span><span style="color: #000000"> </span><span style="color: #A31515">'https://deno.land/x/lazy@v{version}/mod.ts'</span><span style="color: #000000">;</span>
<span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">iterable</span><span style="color: #000000"> = </span><span style="color: #795E26">from</span><span style="color: #000000">([</span><span style="color: #098658">1</span><span style="color: #000000">, </span><span style="color: #098658">2</span><span style="color: #000000">, </span><span style="color: #098658">3</span><span style="color: #000000">, </span><span style="color: #098658">4</span><span style="color: #000000">, </span><span style="color: #098658">5</span><span style="color: #000000">]);</span>
</code></pre>
<p>After you have done this, the full power of the module is available to play with.</p>
<a href="#examples" id="examples" style="color: inherit; text-decoration: none;">
<h2>Examples</h2>
</a>
<p>The aim of the module is to support the full suite of Linq methods the C# provides, as it covers a large surface area with the possible use-cases. Not only does it aim to provide them, it aims to act like them. Nothing is is executed until you call the iterator and start walking through the elements of the list. Here's a small example:</p>
<pre><code class="language-ts"><span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">evenSquares</span><span style="color: #000000"> = </span><span style="color: #001080">Lazy</span><span style="color: #000000">.</span><span style="color: #795E26">range</span><span style="color: #000000">(</span><span style="color: #098658">0</span><span style="color: #000000">, </span><span style="color: #098658">1000</span><span style="color: #000000">)</span>
<span style="color: #000000"> .</span><span style="color: #795E26">where</span><span style="color: #000000">(</span><span style="color: #001080">i</span><span style="color: #000000"> </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #001080">i</span><span style="color: #000000"> % </span><span style="color: #098658">2</span><span style="color: #000000"> === </span><span style="color: #098658">0</span><span style="color: #000000">)</span>
<span style="color: #000000"> .</span><span style="color: #795E26">select</span><span style="color: #000000">(</span><span style="color: #001080">i</span><span style="color: #000000"> </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #001080">i</span><span style="color: #000000"> ** </span><span style="color: #098658">2</span><span style="color: #000000">);</span>
</code></pre>
<p>The result of this chain is an iterator object, however nothing has actually happened yet. As with linq, things only happen exactly when you ask for it:</p>
<pre><code class="language-ts"><span style="color: #AF00DB">for</span><span style="color: #000000"> (</span><span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">num</span><span style="color: #000000"> </span><span style="color: #0000FF">of</span><span style="color: #000000"> </span><span style="color: #001080">evenSquares</span><span style="color: #000000">) {</span>
<span style="color: #000000"> </span><span style="color: #001080">console</span><span style="color: #000000">.</span><span style="color: #795E26">log</span><span style="color: #000000">(</span><span style="color: #001080">num</span><span style="color: #000000">); </span><span style="color: #008000">// 0, 4, 16, 36, 64, 100, 144...</span>
<span style="color: #000000">}</span>
</code></pre>
<p>A huge part of what makes linq so powerful is its composability, which this module provides at a base level:</p>
<pre><code class="language-ts"><span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">selectedEvenNumbers</span><span style="color: #000000"> = </span><span style="color: #001080">evenNumbers</span><span style="color: #000000">.</span><span style="color: #795E26">take</span><span style="color: #000000">(</span><span style="color: #098658">10</span><span style="color: #000000">);</span>
</code></pre>
<p>As with C# Linq, this statement will create a new iteratable object that only returns the first 10 elements of the original iterable object. And the order of composability is not limited, every single method that returns an iterator supports chaining with every other method. On top of this, this module supports the same linq aggregation functions that linq does, for example:</p>
<pre><code class="language-ts"><span style="color: #001080">console</span><span style="color: #000000">.</span><span style="color: #795E26">log</span><span style="color: #000000">(</span><span style="color: #001080">selectedEvenNumbers</span><span style="color: #000000">.</span><span style="color: #795E26">sum</span><span style="color: #000000">()); </span><span style="color: #008000">// -> 1140</span>
</code></pre>
<p>These functions allow you to deal with iterable objects at a high-level, hiding the fact that not all of the values might be available until the iteration is actually done. They also handle things like short-cuts, for example:</p>
<pre><code class="language-ts"><span style="color: #001080">console</span><span style="color: #000000">.</span><span style="color: #795E26">log</span><span style="color: #000000">(</span><span style="color: #001080">Lazy</span><span style="color: #000000">.</span><span style="color: #795E26">range</span><span style="color: #000000">(</span><span style="color: #098658">0</span><span style="color: #000000">, </span><span style="color: #098658">1000</span><span style="color: #000000">).</span><span style="color: #795E26">any</span><span style="color: #000000">(</span><span style="color: #001080">i</span><span style="color: #000000"> </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #001080">i</span><span style="color: #000000"> > </span><span style="color: #098658">100</span><span style="color: #000000">)); </span><span style="color: #008000">// -> true</span>
</code></pre>
<p>This function knows that as soon as the condition is fulfilled, it can stop iterating and hand back the result, saving time with iterating the entire list (which would be easy to forget otherwise).</p>
<p>A primary aim of this library is to allow complex transformations on large datasets without having to deal with the copying that JavaScript normally does, for example:</p>
<pre><code class="language-ts"><span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">data</span><span style="color: #000000"> = </span><span style="color: #795E26">getData</span><span style="color: #000000">(); </span><span style="color: #008000">// Could be a large list of datapoints.</span>
<span style="color: #008000">// Native JS</span>
<span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">points</span><span style="color: #000000"> = </span><span style="color: #001080">data</span>
<span style="color: #000000"> .</span><span style="color: #795E26">map</span><span style="color: #000000">(</span><span style="color: #001080">d</span><span style="color: #000000"> </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #001080">d</span><span style="color: #000000">.</span><span style="color: #001080">x</span><span style="color: #000000">)</span>
<span style="color: #000000"> .</span><span style="color: #795E26">filter</span><span style="color: #000000">(</span><span style="color: #001080">x</span><span style="color: #000000"> </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #795E26">selectPoint</span><span style="color: #000000">(</span><span style="color: #001080">x</span><span style="color: #000000">))</span>
<span style="color: #000000"> .</span><span style="color: #795E26">map</span><span style="color: #000000">(</span><span style="color: #001080">x</span><span style="color: #000000"> </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #795E26">adjustPoint</span><span style="color: #000000">(</span><span style="color: #001080">x</span><span style="color: #000000">));</span>
<span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">avg</span><span style="color: #000000"> = </span><span style="color: #001080">points</span><span style="color: #000000">.</span><span style="color: #795E26">reduce</span><span style="color: #000000">((</span><span style="color: #001080">prev</span><span style="color: #000000">, </span><span style="color: #001080">curr</span><span style="color: #000000">) </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #001080">prev</span><span style="color: #000000"> + </span><span style="color: #001080">curr</span><span style="color: #000000">) / </span><span style="color: #001080">points</span><span style="color: #000000">.</span><span style="color: #001080">length</span><span style="color: #000000">;</span>
<span style="color: #008000">// Lazy iterators</span>
<span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">avg</span><span style="color: #000000"> = </span><span style="color: #001080">Lazy</span><span style="color: #000000">.</span><span style="color: #795E26">from</span><span style="color: #000000">(</span><span style="color: #001080">data</span><span style="color: #000000">)</span>
<span style="color: #000000"> .</span><span style="color: #795E26">select</span><span style="color: #000000">(</span><span style="color: #001080">d</span><span style="color: #000000"> </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #001080">d</span><span style="color: #000000">.</span><span style="color: #001080">x</span><span style="color: #000000">)</span>
<span style="color: #000000"> .</span><span style="color: #795E26">where</span><span style="color: #000000">(</span><span style="color: #001080">x</span><span style="color: #000000"> </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #795E26">selectPoint</span><span style="color: #000000">(</span><span style="color: #001080">x</span><span style="color: #000000">))</span>
<span style="color: #000000"> .</span><span style="color: #795E26">select</span><span style="color: #000000">(</span><span style="color: #001080">x</span><span style="color: #000000"> </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #795E26">adjustPoint</span><span style="color: #000000">(</span><span style="color: #001080">x</span><span style="color: #000000">))</span>
<span style="color: #000000"> .</span><span style="color: #795E26">average</span><span style="color: #000000">();</span>
</code></pre>
<p>The native version will create 3 copies of the array, non of which are used beyond the last to calculate the final average, after which point it is also usless. In contrast, the lazy iterator will only apply the transformations/filters at the exact point they are needed, so no copies are done, and the built-in aggregation function allow for a nicer final calculation.</p>
<a href="#interop-with-native" id="interop-with-native" style="color: inherit; text-decoration: none;">
<h2>Interop with native</h2>
</a>
<p>While all of these functions are good, it would be difficult to integrate them without being about to easily convert back to native JS objects. Fortunately, this module provides just that. Currently there are 2 functions, <code>toArray</code> and <code>toMap</code>, which do pretty much exactly as they seem. You can end a lazy chain with one of these to make it resolve all of the iterators and output a native JS object, which can be then used in consuming code.</p>
<p>On top of this, the entire module is build upon the native JS iteration protocol, meaning that any object that implements that can be used with it with no other changes. Just drop the object into a <code>Lazy.from(...)</code> call, and everything will be available.</p>
<p>The <code>Lazy</code> class is also JSON-serialisable (as a list), meaning that you can simply pass the result of a chain into <code>JSON.stringify</code> and it will stringify correctly.</p>
<a href="#api" id="api" style="color: inherit; text-decoration: none;">
<h2>API</h2>
</a>
<p>Visit <a href="https://luvies.github.io/lazy/">https://luvies.github.io/lazy/</a> for the full documentation.</p>
<p>For an overview of the reference I use for developing this module, visit the <a href="https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable">.NET Linq docs</a>.</p>
<p>As an aside, all of the functions exported from <a href="lib/aggregates.ts">aggregates.ts</a> support taking in any object that implements the <code>Iterator<T></code> iterface, so you can use them without wrapping the iterable around <code>Lazy</code> first if you so wish (although I'd recommend using them through <code>Lazy</code>).</p>
<a href="#promises" id="promises" style="color: inherit; text-decoration: none;">
<h3>Promises</h3>
</a>
<p>This module fully supports promises, and things like for-await-of. As an example (taken from the tests):</p>
<pre><code class="language-ts"><span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">list</span><span style="color: #000000"> = [</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">1</span><span style="color: #000000">),</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">2</span><span style="color: #000000">),</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">3</span><span style="color: #000000">),</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">4</span><span style="color: #000000">),</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">5</span><span style="color: #000000">),</span>
<span style="color: #000000">];</span>
<span style="color: #AF00DB">for</span><span style="color: #000000"> </span><span style="color: #AF00DB">await</span><span style="color: #000000"> (</span><span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">element</span><span style="color: #000000"> </span><span style="color: #0000FF">of</span><span style="color: #000000"> </span><span style="color: #001080">Lazy</span><span style="color: #000000">.</span><span style="color: #795E26">from</span><span style="color: #000000">(</span><span style="color: #001080">list</span><span style="color: #000000">)) {</span>
<span style="color: #000000"> </span><span style="color: #001080">console</span><span style="color: #000000">.</span><span style="color: #795E26">log</span><span style="color: #000000">(</span><span style="color: #001080">element</span><span style="color: #000000">);</span>
<span style="color: #000000">}</span>
<span style="color: #008000">/*</span>
<span style="color: #008000"> Output:</span>
<span style="color: #008000"> -> 1</span>
<span style="color: #008000"> -> 2</span>
<span style="color: #008000"> -> 3</span>
<span style="color: #008000"> -> 4</span>
<span style="color: #008000"> -> 5</span>
<span style="color: #008000">*/</span>
</code></pre>
<p>However, it also supports resolving all promises in the iterable to their values all at once, using the help of <code>Promise.all</code>:</p>
<pre><code class="language-ts"><span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">list</span><span style="color: #000000"> = [</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">1</span><span style="color: #000000">),</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">2</span><span style="color: #000000">),</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">3</span><span style="color: #000000">),</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">4</span><span style="color: #000000">),</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">5</span><span style="color: #000000">),</span>
<span style="color: #000000">];</span>
<span style="color: #AF00DB">for</span><span style="color: #000000"> (</span><span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">element</span><span style="color: #000000"> </span><span style="color: #0000FF">of</span><span style="color: #000000"> (</span><span style="color: #AF00DB">await</span><span style="color: #000000"> </span><span style="color: #001080">Lazy</span><span style="color: #000000">.</span><span style="color: #795E26">from</span><span style="color: #000000">(</span><span style="color: #001080">list</span><span style="color: #000000">).</span><span style="color: #795E26">resolveAll</span><span style="color: #000000">()).</span><span style="color: #795E26">select</span><span style="color: #000000">(</span>
<span style="color: #000000"> </span><span style="color: #001080">i</span><span style="color: #000000"> </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #001080">i</span><span style="color: #000000"> ** </span><span style="color: #098658">2</span><span style="color: #000000">,</span>
<span style="color: #000000">)) {</span>
<span style="color: #000000"> </span><span style="color: #001080">console</span><span style="color: #000000">.</span><span style="color: #795E26">log</span><span style="color: #000000">(</span><span style="color: #001080">element</span><span style="color: #000000">);</span>
<span style="color: #000000">}</span>
<span style="color: #008000">/*</span>
<span style="color: #008000"> Output:</span>
<span style="color: #008000"> -> 1</span>
<span style="color: #008000"> -> 4</span>
<span style="color: #008000"> -> 9</span>
<span style="color: #008000"> -> 16</span>
<span style="color: #008000"> -> 25</span>
<span style="color: #008000">*/</span>
</code></pre>
<p>For TypeScript users, the <code>resolveAll</code> function all also correctly determines the resulting object type, even if there is a mix of promises and non promises:</p>
<pre><code class="language-ts"><span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">list</span><span style="color: #000000"> = [</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">1</span><span style="color: #000000">),</span>
<span style="color: #000000"> </span><span style="color: #098658">2</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">3</span><span style="color: #000000">),</span>
<span style="color: #000000"> </span><span style="color: #098658">4</span>
<span style="color: #000000"> </span><span style="color: #267F99">Promise</span><span style="color: #000000">.</span><span style="color: #795E26">resolve</span><span style="color: #000000">(</span><span style="color: #098658">5</span><span style="color: #000000">),</span>
<span style="color: #000000">]; </span><span style="color: #008000">// type -> Array<number | Promise<number>></span>
<span style="color: #001080">Lazy</span><span style="color: #000000">.</span><span style="color: #795E26">from</span><span style="color: #000000">(</span><span style="color: #001080">list</span><span style="color: #000000">).</span><span style="color: #795E26">resolveAll</span><span style="color: #000000">() </span><span style="color: #008000">// type -> Promise<Lazy<number>></span>
</code></pre>
<a href="#39no-additional-unexpected-iteration39" id="39no-additional-unexpected-iteration39" style="color: inherit; text-decoration: none;">
<h3>'No additional unexpected iteration'</h3>
</a>
<p>For any function on <code>Lazy</code> that uses this term, it simply means 'if you start iteration on the resulting object, it will not perform any iteration you did not ask for'. To put it another way, when you call the iterator function, nothing will happen until you explicitly ask for the next element. This term is used since, for some functions, additional iteration is needed in order to perform the action required. An example of this would be the <code>reverse</code> method; you cannot iterate the first element of the result until you know what the last element of the underlying iterable is, so it has to iterate it completely first before returning the first element. In contrast, the <code>select</code> method will only iterate to the next element when you ask it to, thus it doesn't perform any additional unexpected iteration.</p>
<a href="#custom-implementations" id="custom-implementations" style="color: inherit; text-decoration: none;">
<h3>Custom implementations</h3>
</a>
<p>This module supports using your own lazy iterable implementations in the chain. This is because of the way all of the functions are implemented, which is that they return a new object that extends the <code>Lazy</code> class and only contains the exact properties needed to perform the iteration. This allows you to write a custom implementation that does something unique to the problem you need to solve, and then integrate it into the normal chain. Here is an example implementation:</p>
<pre><code class="language-ts"><span style="color: #0000FF">class</span><span style="color: #000000"> </span><span style="color: #267F99">LazyToString</span><span style="color: #000000"><</span><span style="color: #267F99">TSource</span><span style="color: #000000">> </span><span style="color: #0000FF">extends</span><span style="color: #000000"> </span><span style="color: #267F99">Lazy</span><span style="color: #000000"><</span><span style="color: #267F99">string</span><span style="color: #000000">> {</span>
<span style="color: #000000"> </span><span style="color: #0000FF">public</span><span style="color: #000000"> </span><span style="color: #0000FF">constructor</span><span style="color: #000000">(</span><span style="color: #0000FF">private</span><span style="color: #000000"> </span><span style="color: #0000FF">readonly</span><span style="color: #000000"> </span><span style="color: #001080">_iterable</span><span style="color: #000000">: </span><span style="color: #267F99">Iterable</span><span style="color: #000000"><</span><span style="color: #267F99">TSource</span><span style="color: #000000">>) {</span>
<span style="color: #000000"> </span><span style="color: #0000FF">super</span><span style="color: #000000">();</span>
<span style="color: #000000"> }</span>
<span style="color: #000000"> </span><span style="color: #0000FF">public</span><span style="color: #000000"> </span><span style="color: #0000FF">*</span><span style="color: #000000">[</span><span style="color: #267F99">Symbol</span><span style="color: #000000">.</span><span style="color: #001080">iterator</span><span style="color: #000000">](): </span><span style="color: #267F99">Iterator</span><span style="color: #000000"><</span><span style="color: #267F99">string</span><span style="color: #000000">> {</span>
<span style="color: #000000"> </span><span style="color: #AF00DB">for</span><span style="color: #000000"> (</span><span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">element</span><span style="color: #000000"> </span><span style="color: #0000FF">of</span><span style="color: #000000"> </span><span style="color: #0000FF">this</span><span style="color: #000000">.</span><span style="color: #001080">_iterable</span><span style="color: #000000">) {</span>
<span style="color: #000000"> </span><span style="color: #AF00DB">yield</span><span style="color: #000000"> </span><span style="color: #A31515">`</span><span style="color: #0000FF">${</span><span style="color: #001080">element</span><span style="color: #0000FF">}</span><span style="color: #A31515">`</span><span style="color: #000000">;</span>
<span style="color: #000000"> }</span>
<span style="color: #000000"> }</span>
<span style="color: #000000">}</span>
<span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #795E26">iterableToString</span><span style="color: #000000"> = <</span><span style="color: #267F99">TSource</span><span style="color: #000000">>(</span><span style="color: #001080">t</span><span style="color: #000000">: </span><span style="color: #267F99">Iterable</span><span style="color: #000000"><</span><span style="color: #267F99">TSource</span><span style="color: #000000">>) </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #0000FF">new</span><span style="color: #000000"> </span><span style="color: #267F99">LazyToString</span><span style="color: #000000">(</span><span style="color: #001080">t</span><span style="color: #000000">);</span>
<span style="color: #0000FF">const</span><span style="color: #000000"> </span><span style="color: #0070C1">result</span><span style="color: #000000"> = </span><span style="color: #001080">Lazy</span><span style="color: #000000">.</span><span style="color: #795E26">from</span><span style="color: #000000">([</span><span style="color: #098658">1</span><span style="color: #000000">, </span><span style="color: #098658">10</span><span style="color: #000000">, </span><span style="color: #098658">100</span><span style="color: #000000">, </span><span style="color: #098658">1000</span><span style="color: #000000">])</span>
<span style="color: #000000"> .</span><span style="color: #795E26">apply</span><span style="color: #000000"><</span><span style="color: #267F99">LazyToString</span><span style="color: #000000"><</span><span style="color: #267F99">number</span><span style="color: #000000">>, </span><span style="color: #267F99">string</span><span style="color: #000000">>(</span><span style="color: #001080">iterableToString</span><span style="color: #000000">)</span>
<span style="color: #000000"> .</span><span style="color: #795E26">select</span><span style="color: #000000">(</span><span style="color: #001080">s</span><span style="color: #000000"> </span><span style="color: #0000FF">=></span><span style="color: #000000"> </span><span style="color: #001080">s</span><span style="color: #000000">.</span><span style="color: #001080">length</span><span style="color: #000000">)</span>
<span style="color: #000000"> .</span><span style="color: #795E26">toArray</span><span style="color: #000000">();</span>
<span style="color: #008000">// result -> [1, 2, 3, 4]</span>
</code></pre>
<p>Obviously this is a contrived example, since the same could be done with a single <code>select</code>, but you see the power that is available. You can make any custom implementation at all, and it will chain as if it was part of the API itself.</p>
<a href="#shorthand-usage" id="shorthand-usage" style="color: inherit; text-decoration: none;">
<h3>Shorthand usage</h3>
</a>
<p>If you are using <code>Lazy.from</code> a lot in your code, you can use the following snippet to make usage much more ergonomic:</p>
<pre><code class="language-ts"><span style="color: #0000FF">declare</span><span style="color: #000000"> </span><span style="color: #001080">global</span><span style="color: #000000"> {</span>
<span style="color: #000000"> </span><span style="color: #0000FF">interface</span><span style="color: #000000"> </span><span style="color: #267F99">Array</span><span style="color: #000000"><</span><span style="color: #267F99">T</span><span style="color: #000000">> {</span>
<span style="color: #000000"> </span><span style="color: #008000">/**</span>
<span style="color: #008000"> * Returns the lazy iterator of the current array.</span>
<span style="color: #008000"> */</span>
<span style="color: #000000"> </span><span style="color: #001080">lazy</span><span style="color: #000000">: </span><span style="color: #267F99">Lazy</span><span style="color: #000000"><</span><span style="color: #267F99">T</span><span style="color: #000000">>;</span>
<span style="color: #000000"> }</span>
<span style="color: #000000">}</span>
<span style="color: #267F99">Object</span><span style="color: #000000">.</span><span style="color: #795E26">defineProperty</span><span style="color: #000000">(</span><span style="color: #267F99">Array</span><span style="color: #000000">.</span><span style="color: #001080">prototype</span><span style="color: #000000">, </span><span style="color: #A31515">'lazy'</span><span style="color: #000000">, {</span>
<span style="color: #000000"> </span><span style="color: #795E26">get</span><span style="color: #000000">() {</span>
<span style="color: #000000"> </span><span style="color: #AF00DB">return</span><span style="color: #000000"> </span><span style="color: #001080">Lazy</span><span style="color: #000000">.</span><span style="color: #795E26">from</span><span style="color: #000000">(</span><span style="color: #0000FF">this</span><span style="color: #000000">);</span>
<span style="color: #000000"> },</span>
<span style="color: #000000">});</span>
</code></pre>
<a href="#setting-up-this-project" id="setting-up-this-project" style="color: inherit; text-decoration: none;">
<h2>Setting up this project</h2>
</a>
<p>This project is written primarily for deno, with node support being done via a 2-step compilation process. In order to set up the project, you need to install <a href="https://github.com/denoland/deno">deno</a> globally. To make editing work in VSCode, make sure that you do the following:</p>
<ul>
<li>Run <code>yarn</code> to install the dependencies that VSCode needs to edit properly</li>
<li>Run <code>yarn init-types</code> to grab the types for the testing module</li>
<li>Make sure that VSCode is using the local TypeScript version (bottom right of the editor while opening a <code>.ts</code> file)</li>
<li>Adjust the <a href="tsconfig.json"><code>tsconfig.json</code></a> so that the <code>paths</code> are pointing to the right directory<ul>
<li>They should point to the <code>$HOME/.deno/deps/http</code> and <code>$HOME/.deno/deps/https</code> directories</li>
<li>The path has to be relative due to a TS server limitation</li>
<li><em>DO NOT COMMIT THIS CHANGE</em>, as it only applies to your setup and your setup only</li>
</ul>
</li>
</ul>
<a href="#compatibility" id="compatibility" style="color: inherit; text-decoration: none;">
<h3>Compatibility</h3>
</a>
<p>As mentioned before, this module is fully compatible with normal ES2015 iterators and native arrays/maps. It targets ES2015, meaning that if you need to support ES5 & earlier, you will need to use a transpiler like babel. For Node.js, it requires about v6 or higher (not properly tested on this version though).</p>
<a href="#footnotes" id="footnotes" style="color: inherit; text-decoration: none;">
<h2>Footnotes</h2>
</a>
<p>Massive thanks to the .NET Core team and their work on Linq, the source reference was invaluable when implementing some of the methods here.</p>
</div>
</div>
<div class="col-4 col-menu menu-sticky-wrap menu-highlight">
<nav class="tsd-navigation primary">
<ul>
<li class=" ">
<a href="modules.html">Exports</a>
</li>
</ul>
</nav>
<nav class="tsd-navigation secondary menu-sticky">
<ul class="before-current">
<li class=" tsd-kind-class tsd-has-type-parameter">
<a href="classes/lazy.html" class="tsd-kind-icon">Lazy</a>
</li>
<li class=" tsd-kind-function tsd-has-type-parameter">
<a href="modules.html#empty" class="tsd-kind-icon">empty</a>
</li>
<li class=" tsd-kind-function tsd-has-type-parameter">
<a href="modules.html#from" class="tsd-kind-icon">from</a>
</li>
<li class=" tsd-kind-function">
<a href="modules.html#range" class="tsd-kind-icon">range</a>
</li>
<li class=" tsd-kind-function tsd-has-type-parameter">
<a href="modules.html#repeat" class="tsd-kind-icon">repeat</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<footer class="with-border-bottom">
<div class="container">
<h2>Legend</h2>
<div class="tsd-legend-group">
<ul class="tsd-legend">
<li class="tsd-kind-method tsd-parent-kind-class"><span class="tsd-kind-icon">Method</span></li>
</ul>
<ul class="tsd-legend">
<li class="tsd-kind-method tsd-parent-kind-class tsd-is-static"><span class="tsd-kind-icon">Static method</span></li>
</ul>
</div>
</div>
</footer>
<div class="container tsd-generator">
<p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p>
</div>
<div class="overlay"></div>
<script src="assets/js/main.js"></script>
</body>
</html>