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

@simpill/collections.utils

v1.0.0

Published

Type-safe LinkedList, Queue, Stack, LRU/TTL, MultiMap, BiMap—no full collections lib (Node and Edge).

Readme

Features: Type-safe · Node & Edge · Tree-shakeable · Lightweight


Installation

From npm

npm install @simpill/collections.utils

From GitHub

To use this package from the monorepo source:

git clone https://github.com/SkinnnyJay/simpill.git
cd simpill/utils/@simpill-collections.utils
npm install && npm run build

In your project you can then install from the local path: npm install /path/to/simpill/utils/@simpill-collections.utils or use npm link from the package directory.


Usage

Subpath exports

import {
  LinkedList,
  Vector,
  Queue,
  Stack,
  Deque,
  CircularBuffer,
  LRUCache,
  TTLCache,
  MultiMap,
  BiMap,
  OrderedMap,
  TypedSet,
} from "@simpill/collections.utils";

// or shared only
import { Queue, Stack } from "@simpill/collections.utils/shared";

Contracts

Shared interfaces for consistent APIs:

  • ICollection<T>size, isEmpty(), clear(), toArray(), [Symbol.iterator]
  • IIndexable<T>get(index), set(index, value), at(index)
  • Equatable<T> / Hasher<T> – optional custom equality/hash for maps and sets

LinkedList

Doubly linked list. O(1) insert/remove at head/tail.

import { LinkedList } from "@simpill/collections.utils";

const list = LinkedList.fromArray([1, 2, 3]);
list.push(4);
list.unshift(0);
list.insertAt(2, 99);
list.removeAt(1);
console.log(list.toArray());

Vector

Dynamic array with explicit capacity and index access.

import { Vector } from "@simpill/collections.utils";

const v = new Vector<number>(8);
v.push(1);
v.push(2);
v.reserve(16);
v.shrinkToFit();
console.log(v.get(0), v.at(-1));

Queue (FIFO) and Stack (LIFO)

import { Queue, Stack } from "@simpill/collections.utils";

const queue = new Queue<number>();
queue.enqueue(1);
queue.enqueue(2);
queue.dequeue(); // 1

const stack = new Stack<number>();
stack.push(1);
stack.push(2);
stack.pop(); // 2

Deque

Double-ended queue. Push/pop at both ends.

import { Deque } from "@simpill/collections.utils";

const d = new Deque<number>();
d.pushBack(1);
d.pushFront(0);
d.popBack(); // 1
d.popFront(); // 0

CircularBuffer

Fixed-capacity ring buffer. Oldest entries dropped when full.

import { CircularBuffer } from "@simpill/collections.utils";

const b = new CircularBuffer<number>(3);
b.push(1);
b.push(2);
b.push(3);
b.push(4); // 1 is dropped
b.shift(); // 2

LRUCache

Size-bounded cache with least-recently-used eviction.

import { LRUCache } from "@simpill/collections.utils";

const cache = new LRUCache<string, number>(100);
cache.set("a", 1);
cache.get("a"); // 1; touch
cache.set("b", 2);
// when over maxSize, oldest is evicted

TTLCache

Entries expire after a TTL (ms). Optional maxSize with LRU eviction. Expired entries are pruned on set(), get(), and when reading size; prune is O(n) in the number of entries, so when many entries are expired, these operations may be slow.

import { TTLCache } from "@simpill/collections.utils";

const cache = new TTLCache<string, number>({ ttlMs: 60_000, maxSize: 500 });
cache.set("a", 1);
cache.get("a"); // 1 within TTL

MultiMap

One key maps to multiple values.

import { MultiMap } from "@simpill/collections.utils";

const m = new MultiMap<string, number>();
m.add("tags", 1);
m.add("tags", 2);
m.get("tags"); // [1, 2]

BiMap

Bidirectional map. Key and value are both unique.

import { BiMap } from "@simpill/collections.utils";

const b = new BiMap<string, number>();
b.set("id", 100);
b.getByKey("id"); // 100
b.getByValue(100); // "id"

OrderedMap

Map with insertion order; access by key or by index.

import { OrderedMap } from "@simpill/collections.utils";

const m = new OrderedMap<string, number>();
m.set("a", 1);
m.set("b", 2);
m.getAt(0); // ["a", 1]
m.keyAt(1); // "b"

TypedSet

Set with optional custom equality and validator.

import { TypedSet } from "@simpill/collections.utils";

const s = new TypedSet<{ id: number }>({
  equals: (a, b) => a.id === b.id,
  validate: (x) => x.id > 0,
});
s.add({ id: 1 });
s.add({ id: 1 }); // no duplicate

Examples

npx ts-node examples/01-basic-usage.ts

| Example | Description | |---------|-------------| | 01-basic-usage.ts | Queue, Stack, LinkedList, Vector, Deque, CircularBuffer, LRUCache, TTLCache, MultiMap, BiMap, OrderedMap, TypedSet |

API summary

| Structure | Description | |----------------|--------------------------------| | LinkedList | Doubly linked list | | Vector | Dynamic array, capacity | | Queue | FIFO (backed by Deque) | | Stack | LIFO (backed by Deque) | | Deque | Double-ended queue | | CircularBuffer | Fixed-capacity ring buffer | | LRUCache | Max-size LRU cache | | TTLCache | TTL expiry, optional maxSize | | MultiMap | Key → multiple values | | BiMap | Bidirectional K ↔ V | | OrderedMap | Insertion order + index access | | TypedSet | Set with equals/validate |

Complexity (typical)

| Structure | get/set/access | insert/remove (head/tail) | iteration | |----------------|----------------|---------------------------|-----------| | LinkedList | O(n) by index | O(1) head/tail | O(n) | | Vector | O(1) | O(1) amortized push/pop | O(n) | | Queue / Stack | — | O(1) enqueue/dequeue etc. | O(n) | | Deque | — | O(1) both ends | O(n) | | CircularBuffer | O(1) by index | O(1) push/shift | O(n) | | LRUCache | O(1) get/set | O(1) eviction | O(n) | | TTLCache | O(1) get/set | Expiry prune on get/size | O(n) | | OrderedMap | O(1) get | O(1) set | O(n) | | TypedSet | O(n) has | O(n) add (no hash) | O(n) |

Iteration and serialize

Structures implementing ICollection provide toArray() and Symbol.iterator; use them for iteration or serialization (e.g. JSON.stringify(cache.toArray()) only if values are serializable). Map-like types (LRUCache, TTLCache, OrderedMap, BiMap, MultiMap) expose entries/keys/values where applicable; see type definitions.

Thread-safety

All structures are not thread-safe; they assume single-threaded JS. For shared state across workers use message passing or a concurrency primitive.

Priority queue / sorted map / immutable

This package does not provide a priority queue (heap), sorted map/set, or persistent/immutable structures. Use a dedicated library (e.g. heap-based PQ, or immutable.js) if needed.

Hasher and Equatable

Equatable<T> = (a, b) => boolean — used by TypedSet (options.equals). Hasher<T> = (value) => string | number — for key hashing in hash-based structures; not all structures accept it (TypedSet uses equality only). Use equals for set membership when reference equality is not enough; use Hasher where a structure supports it for O(1) key lookups with custom keys.

LRU / TTL and overlap with cache.utils

LRUCache and TTLCache here are in-memory, sync structures. @simpill/cache.utils provides InMemoryCache, TTLCache, memoizeAsync, and Redis-style adapters with a different API (get/set/delete). Use collections.utils when you want these data structures as building blocks; use cache.utils when you want a cache abstraction with optional async backends and memoization.

LRU/TTL performance notes

LRUCache: get/set and eviction are O(1). TTLCache: expired entries are pruned on get(), set(), and when reading size, so growth is bounded by reads or writes. Prefer maxSize with TTLCache when you want a cap in addition to TTL.

What we don't provide

  • Priority queue / heap — No PQ or heap; use a dedicated library.
  • Sorted map / sorted set — No order-by-key structures; use OrderedMap for insertion order or an external sorted collection.
  • Immutable / persistent structures — All structures are mutable; for immutability use a library (e.g. immutable.js).
  • Thread-safety — Single-threaded JS only; use message passing or primitives for cross-worker state.

Development

npm run build
npm test
npm run test:coverage
npm run check:fix
npm run verify

Documentation

License

ISC