npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

zilt

v2.1.1

Published

A lazy iterator library in TypeScript.

Readme

Build Downloads LastCommit Stars

Presentation

zilt is a TypeScript lazy iterator library. It lets you create iterators with useful utility methods for declarative-style data processing. The library uses ES6 generators under the hood and has no dependencies.

Some great iterator libraries already exist, why create another one?

  • To learn about ES6 generators
  • To learn about creating, publishing and maintaining open-source libraries
  • For fun

Installation

npm install zilt
// ESM
import * as zilt from "zilt";

// CommonJS
const zilt = require("zilt");

Example

Let's consider the following exercise: given a non-empty height * width matrix full of .'s, draw a zigzag pattern of O's inside the matrix and return it. This is a contrived example, but it helps demonstrate the capabilities of zilt iterators.

const input = [
    [".", ".", ".", ".", ".", ".", ".", ".", "."],
    [".", ".", ".", ".", ".", ".", ".", ".", "."],
    [".", ".", ".", ".", ".", ".", ".", ".", "."],
    [".", ".", ".", ".", ".", ".", ".", ".", "."],
];

const output = [
    ["O", ".", ".", "O", ".", ".", "O", ".", "."],
    ["O", ".", "O", "O", ".", "O", "O", ".", "O"],
    ["O", "O", ".", "O", "O", ".", "O", "O", "."],
    ["O", ".", ".", "O", ".", ".", "O", ".", "."],
];

To visit the cells that need to be replaced with an O, we want to iterate over matrix positions starting from [0, 0] moving either down or to the top right at each iteration.

With [ystep, xstep] denoting a vertical ystep move + a horizontal xstep move, the step algorithm can be described as follows:

  • height - 1 vertical steps down ([ystep, xstep] = [1, 0]) are taken to reach the bottom of the matrix
  • height - 1 diagonal steps to the top right ([ystep, xstep] = [-1, 1]) are taken to reach the top again
  • Repeat

We can create a zilt iterator over the infinite step sequence from above using the .stretch() and .cycle() methods.

function draw(matrix, height, width) {
    const down = [1, 0];
    const up = [-1, 1];

    const steps = zilt.iter([down, up]) // [down, up]
        .stretch(height - 1) // [down * (height - 1), up * (height - 1)]
        .cycle(); // repeat the above to infinity

    ...
}

From there, we just need to initialize some matrix coordinates to [0, 0] and apply each directional step to it in order to loop over the relevant cells and overwrite their content with O's. Since the iterator loops indefinitely, we need to make sure to stop the drawing loop once the current coordinate is out of the matrix bounds.

function draw(matrix, height, width) {
    const down = [1, 0];
    const up = [-1, 1];

    const steps = zilt
        .iter([down, up])
        .stretch(height - 1)
        .cycle();

    let [y, x] = [0, 0];
    for (const [ystep, xstep] of steps) {
        if (x >= width) break;

        matrix[y][x] = "O";
        [y, x] = [y + ystep, x + xstep];
    }

    return matrix;
}

I would advise against writing code in this style, but here's another way of solving this problem using zilt exclusively.

function draw(matrix, height, width) {
    const down = [1, 0];
    const up = [-1, 1];

    const steps = zilt
        .iter([down, up])
        .stretch(height - 1)
        .cycle();

    zilt.once([0, 0])
        .chain(steps)
        .accumulate(([y, x], [ys, xs]) => [y + ys, x + xs])
        .takeWhile(([_, x]) => x < width)
        .forEach(([y, x]) => (matrix[y][x] = "O"));

    return matrix;
}

Documentation

Builders

iter()

Creates an iterator from an iterable.

// [0, 1, 2]
zilt.iter([0, 1, 2]).collect();

once()

Creates an iterator over a single value.

// [['hello']]
zilt.once(["hello"]).collect();

range()

Creates an iterator over a range of numbers (end excluded).

zilt.range().collect(); // [0, 1, ...] (infinite)
zilt.range(1, 4).collect(); // [1, 2, 3]
zilt.range(3, 0).collect(); // [3, 2, 1]
zilt.range(4).collect(); // [0, 1, 2, 3]
zilt.range(-4).collect(); // [0, -1, -2, -3]

chain()

Creates an iterator that yields the values of each passed iterable in sequence.

// [0, 1, 'foo']
zilt.chain([0, 1], ["foo"]).collect();

zip()

Creates an iterator over n-tuples from "merging" n iterators together.

// [[0, 6, "foo"], [1, 7, "bar"]]
zilt.zip([0, 1], [6, 7], ["foo", "bar"]).collect();

Consumer methods

.collect()

Consumes the iterator to collect its values in an array and returns it.

// [0, 1, 2]
zilt.range(0, 3).collect();

.forEach()

Consumes the iterator, invoking the provided function for each element.

// prints 0, 1, 2
zilt.range(0, 3).forEach((n, i) => console.log(n));

.find()

Partially consumes the iterator and returns the first element for which the predicate is true. Returns undefined if none was found.

// 6
zilt.iter([7, 11, 3, 6, 5]).find((n) => n % 2 === 0);

.position()

Partially consumes the iterator and returns the index of the first element for which the predicate is true. Returns undefined if none was found.

// 3
zilt.iter([7, 11, 3, 6, 5]).position((n) => n % 2 === 0);

.reduce()

Consumes the iterator to produce a single value using a given function.

// 6
zilt.range(0, 4).reduce((acc, n) => acc + n);

// 7
zilt.range(0, 4).reduce((acc, n) => acc + n, 1);

// '0123'
zilt.range(0, 4).reduce((acc, n) => acc + n.toString(), "");

.count()

Consumes the iterator and returns the number of elements that match a predicate.

// 3
const arr = [10, 15, 15, 20];
zilt.iter(arr).count(); // 4
zilt.iter(arr).count((n) => n === 15); // 2

.nth()

Partially consumes the iterator and returns its nth element (0-indexed).

zilt.iter([1, 2, 3]).nth(2); // 3

.first()

Partially consumes the iterator and returns its first element.

zilt.iter([1, 2, 3]).first(); // 1

.last()

Consumes the iterator and returns its last element.

zilt.iter([1, 2, 3]).last(); // 3

.min()

Consumes the iterator and returns the element for which the getKey function result is the minimum.

zilt.iter([3, 6, 4, 1, 8]).min((n) => n); // 1
zilt.iter([3, 6, 4, 1, 8]).min((n) => -n); // 8

.max()

Consumes the iterator and returns the element for which the getKey function result is the maximum.

zilt.iter([3, 6, 4, 1, 8]).max((n) => n); // 8
zilt.iter([3, 6, 4, 1, 8]).max((n) => -n); // 1

.some()

Consumes the iterator and returns true if any element satisfies the predicate.

zilt.iter([1, 1, 2]).some((n) => n === 2); // true
zilt.iter([1, 1, 1]).some((n) => n === 2); // false

.every()

Consumes the iterator and returns true if every element satisfies the predicate.

zilt.iter([1, 2, 2]).every((n) => n === 2); // false
zilt.iter([2, 2, 2]).every((n) => n === 2); // true

.unzip()

Consumes an iterator over n-tuples and returns n arrays.

// [[0, 1, 2], [3, 4, 5]]
zilt.iter([
    [0, 3],
    [1, 4],
    [2, 5],
]).unzip();

.partition()

Consumes the iterator and returns a pair of arrays.

  • the first array contains all elements for which the predicate is true
  • the second array contains all elements for which the predicate is false
// [[2, 4], [1, 3]]
zilt.iter([1, 2, 3, 4]).partition((n) => n % 2 === 0);

.consume()

Consumes the iterator.

// void
zilt.range(0, 3).consume();

Adapter methods

.enumerate()

Creates an iterator yielding values with an index counter starting from 0.

// [[4, 0], [5, 1], [6, 2]]
zilt.iter([4, 5, 6]).enumerate().collect();

.filter()

Creates an iterator which uses a callback to determine if an element should be yielded.

// [1, 3]
zilt.range(0, 4)
    .filter((n) => n % 2 === 1)
    .collect();

.map()

Creates an iterator that transforms each value in the original iterator using the passed function parameter.

// [0, 2, 4, 6]
zilt.range(0, 4)
    .map((n) => n * 2)
    .collect();

.flat()

Creates an iterator which flattens nested array elements up to a certain depth (maxDepth).

NOTE: this method only accepts number literals for the maxDepth parameter in order to correctly infer the output iterator element type.

const array = [
    [0, 1],
    [2, [3]],
];
// [0, 1, 2, [3]]
zilt.iter(arr).flat(1).collect();

// [0, 1, 2, 3]
zilt.iter(arr).flat(2).collect();

.flatMap()

Creates an iterator which is equivalent to .map().flat(1)

// [1, -1, 2, -2]
zilt.iter([1, 2])
    .flatMap((n) => [n, -n])
    .collect();

.take()

Creates an iterator which only keeps the first num values.

// [0, 1, 2]
zilt.range(0, 6).take(3).collect();

.takeWhile()

Creates an iterator which yields values until a predicate is false.

// [0, 1, 2]
zilt.range(0, 6)
    .takeWhile((n) => n < 3)
    .collect();

.skip()

Creates an iterator which skips the first num values.

// [3, 4, 5]
zilt.range(0, 6).skip(3).collect();

.skipWhile()

Creates an iterator which skips values while a predicate is true.

// [3, 4, 5]
zilt.range(0, 6)
    .skipWhile((n) => n < 3)
    .collect();

.slice()

Creates an iterator which only yields elements from start to end (excluded). It is equivalent to .skip(start).take(end - start).

// [1, 2]
zilt.iter([0, 1, 1, 2, 3]).slice(2, 4).collect();

.step()

Creates an iterator that yields values by steps of step starting from the first element.

// [1, 4, 7]
zilt.range(1, 10).step(3).collect();

.chain()

Creates an iterator that extends the current iterator with the values of each passed iterable in sequence.

// [0, 'foo', 'bar']
zilt.iter([0]).chain(["foo"], ["bar"]).collect();

.cycle()

Creates an iterator that repeats the current iterator count times. count defaults to Infinity.

// [1, 2, 3, 1, 2, 3]
zilt.range(1, 4).cycle(2).collect();

// [1, 2, 3, 1, 2, 3, 1, 2]
zilt.range(1, 4).cycle().take(8).collect();

.stretch()

Creates an iterator that repeats each value of the current iterator count times.

// [1, 1, 2, 2, 3, 3]
zilt.iter([1, 2, 3]).stretch(2).collect();

.nest()

Creates an iterator which repeats the provided iterable for each element in the current iterator. Elements are yielded as pairs.

NOTE: prefer using .nest(start, end) instead of .nest(range(start, end)) to avoid the unnecessary buffering of iterable values.

// [[0, 'a'], [0, 'b'], [1, 'a'], [1, 'b']]
zilt.range(2).nest(["a", "b"]).collect();

// [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]
zilt.range(2).nest(3).collect();

// [[0, 0], [0, -1], [1, 0], [1, -1]]
zilt.range(2).nest(0, -2).collect();

.zip()

Creates an iterator over n-tuples from "merging" n iterators together.

// [[0, 6, "foo"], [1, 7, "bar"]]
zilt.iter([0, 1]).zip([6, 7], ["foo", "bar"]).collect();

.chunks()

Creates an iterator which yields elements by chunks of k.

// [[0, 1], [2, 3], [4]]
zilt.iter([0, 1, 2, 3, 4]).chunks(2).collect();

.windows()

Creates an iterator which yields every consecutive k-element window.

// [[0, 1], [1, 2], [2, 3], [3, 4]]
zilt.iter([0, 1, 2, 3, 4]).windows(2).collect();

.accumulate()

Creates an iterator which updates and yields an accumulator using the provided function (similar to reduce, but yields the accumulator at every step instead of returning the final accumulator value).

// [0, 1, 3, 6, 10]
zilt.range(0, 5)
    .accumulate((acc, n) => acc + n)
    .collect();

.unique()

Creates an iterator which filters out duplicate values.

// [0, 1, 2, 3, 4]
zilt.iter([0, 1, 1, 2, 3, 2, 4]).unique().collect();

.uniqueBy()

Creates an iterator which filters out duplicate values using a getKey function.

// [0, 1, 2, 3, 4]
zilt.iter([0, 1, 1, 2, 3, 2, 4])
    .uniqueBy((n) => n)
    .collect();

.inspect()

Creates an iterator that invokes a callback on each element before yielding.

// [1, 10, 2, 20, 3, 30]
const out: number[] = [];

zilt.range(1, 4)
    .inspect((n) => out.push(n))
    .map((n) => n * 10)
    .inspect((n) => out.push(n))
    .consume();

Contributing

Any contributions you make are greatly appreciated.

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!