JSPM

  • Created
  • Published
  • Downloads 61
  • Score
    100M100P100Q61827F
  • License MIT

The easiest way to handle iterables.

Package Exports

  • doddle

Readme

Doddle

Doddle workflow status Doddle package version Doddle Coveralls Doddle minified size(gzip)

Doddle is a tiny and powerful library for lazy computation. It's inspired by lodash, rxjs, and .NET's LINQ.

Sync and async

Complete support for async iterables.

Doddle provides two wrapper types --

  • Seq --- Manipulates sync iterables, created using the seq factory function.
  • ASeq --- Manipulates async iterables, created using the aseq factory function.

While they're different types, they provide a nearly identical API, with the same set of operators, just different return types.

Seq

const pairsSync = seq([1, 2, 3, 4])
    .map(x => x + 1)
    .chunk(2)

for (const [a, b] of pairsSync) {
    console.log(`${a}, ${b}`)
}

You first convert an existing iterable to a Seq using the seq factory function. This gives you access to a host of powerful and comprehensively tested operators, implemented as convenient instance methods.

All operators are lazy -- which means they have to be evaluated explicitly. This usually means iterating over the Seq.

The seq factory function accepts a range of other inputs besides iterables. You can give it iterators, generator functions, and just functions that return collections.

seq([1, 2, 3])

seq(function* () {
    yield 1
    yield 2
    yield 3
})

seq(() => [1, 2, 3])

You can construct sequences using methods defined on the seq factory function itself.

seq.range(1, 10) // Gives the range 1 .. 10

seq.of(1, 2, 3, 5) // Specify elements explicitly

ASeq

const pairsAsync = aseq([1, 2, 3, 4])
    .map(x => x + 1)
    .chunk(2)

for await (const [a, b] of pairsAsync) {
    console.log(`${a}, ${b}`)
}

This wrapper lets you manipulate async iterables just like sync ones. It supports the same set of methods, just with different return types!

Laziest of them all

Doddle is the laziest library.

Doddle doesn't provide any eager operations. Operators like find or includes, which normally iterate immediately, instead return Doddle's elegant lazy primitive, so invoking them doesn't do anything by itself.

You have to pull the lazy primitive (which is also called a Doddle) to evaluate the operator, giving you explicit control over when iteration occurs.

It's perfect for when iteration causes side-effects, such as dealing with binary streams, generator functions, and database query results.

import { seq, type Doddle } from "doddle"

// This returns the Doddle lazy primitive:
const mySeq: Doddle<number> = seq([1, 2, 3, 4]).includes(2)

// This *pulls* the value out of it:
console.log(mySeq.pull())

Flexible inputs

Doddle works with a wide variety of inputs, which it will carefully normalize

  • Iterable collections
  • Other iterables
  • Generator functions and functions returning

Instance methods

Here is an example of using Doddle to manipulate an iterable.

import { seq } from "doddle"
function* iterable() {
    yield* [1, 2, 3, 4, 5, 6]
}
const it = seq(iterable)
    .filter(x => x % 2 == 0)
    .chunk(2)

for (const [a, b] of it) {
    console.log(`First is ${a} second is ${b}`)
}

Doddle is complete

Doddle is a single complete package for manipulating sequences. You can't import specific operators like in rxjs or lodash -- they're all instance methods, more or less entirely contained in several big files.

Doddle can get away with it by being ridiculously small. Tests have shown that making it tree-shakable on that level greatly increases bundle size.

When you use doddle, you don't pick and choose the functionality you expect you need

Doddle aims to be a complete package for manipulating sequences. You don't need to pick the specific functionality you need because the package is so small tree-shaking it on that level will just increase the bundle size.

Doddle consists of three modules that are tree-shakeable

It also introduces a simple yet elegant lazy primitive, the doddle. It works for both

Doddle is a tiny but incredibly versatile library for working with collections and iterables, inspired by LINQ, lodash, rxjs, and other libraries. It also introduces its own simple yet elegant lazy primitive, which has many of the same qualities as a promise.

Doddle reproduces much of lodash's functionality for working with collections, but it's absolutely tiny. It offers its operators as instance methods because breaking them up into separate files has been shown to increase bundle size through overhead.

However, becuase it operates on iterables rather than on arrays directly, it will most likely be outperformed by other libraries.

Doddle is extensively tested, with over 1000 individual test cases. It also has a suite of compile-time tests that check the logic of its type definitions.

Doddle has been designed to be debuggable. It produces readable stack traces that mirror the code you write, and you can easily jump to, inspect, and place breakpoints in its source code.