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

@hanako-eo/itero

v0.1.0

Published

An iterator library to reduce the execution time of sequential iterators in native javascript

Readme

itero

Itero is a library designed to make iterations easier and more efficient.

This code

const a = [0, 1, 2, 3, 4]
    .map((x) => x * x)
    .filter((x) => x % 2 === 0) // [0, 4, 16]

is simple, but has a big problem, to get it you have to make 2 loops, whereas it's very easy to see that it can be done via a loop,

const a = []
for (const x in [0, 1, 2, 3, 4]) {
    const x2 = x * x
    if (x2 % 2 === 0) a.push(x2)
}
a // [0, 4, 16]

but it's not always easy to see if it's possible with less loops than with.

To make loops easier and keep the methods chainages, Itero proposes to do the following:

const a = [0, 1, 2, 3, 4].iter() // or new ArrayLikeIterator([0, 1, 2, 3, 4])
    .map((x) => x * x)
    .filter((x) => x % 2 === 0)
    .consume().toArray()

Install

npm install @hanako-eo/itero

API

Itero provides an easy "empty" iterface to handle iteration (in a context where Itero is used) IteroIterable (supporting async iteration). Itero also provides the abstract class BaseIterator which provides a default implementation of nth and asyncNth and by the same token provides methods such as .map, .filter and others.

.potentialSize is an obtional method of IteroIterable which gives an idea of the size of the iterator without consuming it, for objects like ArrayLikeIterator it is exact but with IterableIterator it is -1 because it is not calculable without consuming the iterator.

Consumer (exported)

Take an IteroIterator and consume the iterator with methods like first, last, find and others. Here is the list of methods:

first(): Maybe<T>;
last(): Maybe<T>;
firstAndLast(): [Maybe<T>, Maybe<T>];
find(predicate: (v: T) => boolean): Maybe<T>;
count(): number;
sum(): Maybe<T>; // equivalent a reduce((a, b) => a + b)
product(): Maybe<T>; // equivalent a reduce((a, b) => a * b)
sort(compareFn: (a: T, b: T) => number): Array<T>;
compare(compareFn: (a: T, b: T) => boolean): Maybe<T>;
fold<A>(defaultValue: A, callback: (acc: A, value: T) => A): A;
reduce(callback: (acc: T, value: T) => T): Maybe<T>;
forEach(callback: (value: T, index: number, iter: IteroIterable<T>) => void): void;
toArray(): Array<T>;

Map / Filter / Flatten (via .map / .filter / .flatten)

const array = new ArrayLikeIterator([[0, 1], [2, 3], [4, 5, 6]])
    .flatten() // transform [[0, 1], [2, 3], [4, 5, 6]] => [0, 1, 2, 3, 4, 5, 6]
    .map((x) => x + 1) // [0, 1, 2, 3, 4, 5, 6] => [1, 2, 3, 4, 5, 6, 7]
    .filter((x) => x % 2 == 0) // [1, 2, 3, 4, 5, 6, 7] => [2, 4, 6]
    .consume()
    .toArray()

console.log(array) // [2, 4, 6]

work like .map, .filter and .flatten (on arrays, the method is called .flat) on vanilla js arrays, but the callback only takes the element.

Chunk / ChunkExact / Window

The three functions return arrays of size size given as a parameter. However, the internal functioning within the next is not exactly the same.

.chunk creates an array with as many elements as possible up to the size size, but if we haven't reached the end (meaning we can't make an array of size size), then it will create with a smaller size. The chunks start at the beginning, and the subsequent chunks start after the previous one:

// for a chunk of size 3
   [0,1,2,3,4,5, 6]
    | 1 | | 2 | |3|
    ----- ----- ---
// or
[0, 1, 2, 3, 4, 5, 6] => [[0, 1, 2], [3, 4, 5], [6]]

Similarly, .chunkExact works like .chunk, but the chunks must be exactly of size size.

// for a chunk of size 3
   [0,1,2,3,4,5, 6]
    | 1 | | 2 | |3| <-- "ignored"
    ----- ----- ---
// or
[0, 1, 2, 3, 4, 5, 6] => [[0, 1, 2], [3, 4, 5]]

The ignored chunk is recoverable with the method .rest.

And for .window, it creates an array of size size but with an offset of 1 and not a complete chunk like .chunk and .chunkExact.

// for a chunk of size 3
   [0,1,2,3,4,5,6]
    | 1 |
      | 2 |
        | 3 |
          | 4 |
            | 5 |
// or
[0, 1, 2, 3, 4, 5, 6] => [[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5], [4, 5, 6]]

Chain / Zip / Enumerate

Chain and Zip both take two iterators.

.chain loops over the first iterator, and as soon as it finishes, it moves to the second one.

.zip combines the two iterators; a next from the zip will call the next on both iterators and give a tuple with the two values or nothing.

.enumerate performs a .zip between a Range and the base iterator (it provides indexing to the elements).

Cycle

Repeats an iterator infinitely. Instead of stopping at a Maybe.none(), the iterator restarts from the beginning. After iterating again, it will start over from the beginning. And again. Ad infinitum. If the original iterator is empty, the resulting iterator will also be empty.

Awaiter (via .await)

Transforms a synchronous iterator into an asynchronous iterator (and at the same time, if next returns a Promise, then .await will wait for the completion of the Promise).

Fuse

Generates an iterator that terminates after the first Maybe.none. Once an iterator returns Maybe.none, subsequent calls may or may not produce another Maybe.some. .fuse modifies an iterator, ensuring that after it has yielded Maybe.none, it always returns Maybe.none indefinitely."

StepBy

Starts from the beginning and yields every element spaced by n elements

// for n = 3
[0, 1, 2, 3, 4, 5, 6] => [0, 3, 6]

Peekable

Creates an iterator that can utilize the .peek method to observe the next element of the iterator without consuming it.

Scan

Works like the scan in rust

An iterator adapter which, like fold, holds internal state, but unlike fold, produces a new iterator.

.scan takes two arguments: an initial value which seeds the internal state, and a closure with two arguments, the first being a mutable reference to the internal state and the second an iterator element. The closure can assign to the internal state to share state between iterations.

Range

Works like the range in Python

Gives 3 statics methods from, exclusive, inclusive to create 3 types of ranges (the step is by default to 1).

from is like [start; Infinity) in maths. exclusive is like [start; end) in maths. inclusive is like [start; end] in maths.

LICENCE

MIT