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

@silencedis/sorted-linked-list

v1.0.0

Published

A stable, always-sorted doubly linked list for TypeScript and modern JavaScript.

Downloads

132

Readme

@silencedis/sorted-linked-list

npm version CI license

A dependency-free doubly linked list that maintains comparator-defined order and preserves insertion order among equivalent values.

Why this implementation?

Unlike a conventional linked list, this collection maintains comparator-defined order as elements are inserted.

  • Always sorted: every insertion is placed according to a comparator.
  • Stable equivalent ordering: values for which the comparator returns 0 retain their insertion order.
  • Efficient boundary operations: insertion at either boundary is constant-time. Ascending streams naturally append to the tail, while descending streams prepend to the head.
  • Ordered access and traversal: inspect or extract either boundary, or iterate from head to tail.
  • No runtime dependencies: the package contains only ESM JavaScript and TypeScript declarations and does not depend on Node.js APIs.

Installation

npm install @silencedis/sorted-linked-list

The package is ESM-only:

import {
    SortedLinkedList,
    type Comparator,
} from '@silencedis/sorted-linked-list';

Quick start

import { SortedLinkedList } from '@silencedis/sorted-linked-list';

const numbers = new SortedLinkedList<number>();

numbers.insert(30);
numbers.insert(10);
numbers.insert(20);
numbers.insert(20);

console.log([...numbers].map(({element}) => element));
// [10, 20, 20, 30]

console.log(numbers.showHead()); // 10
console.log(numbers.showTail()); // 30

The default comparator uses JavaScript's < and > operators. Supply a custom comparator for objects, descending order, or domain-specific ordering.

Custom ordering and stable equivalents

import {
    SortedLinkedList,
    type Comparator,
} from '@silencedis/sorted-linked-list';

interface WorkItem {
    name: string;
    priority: number;
}

const byDescendingPriority: Comparator<WorkItem> = (a, b) => {
    return b.priority - a.priority;
};

const work = new SortedLinkedList(byDescendingPriority);

work.insert({name: 'routine', priority: 1});
work.insert({name: 'first urgent', priority: 10});
work.insert({name: 'second urgent', priority: 10});

console.log([...work].map(({element}) => element.name));
// ['first urgent', 'second urgent', 'routine']

Comparator-equivalent entries preserve their insertion order.

API

new SortedLinkedList<E>(comparator?)

Creates an empty list. A comparator follows the same sign convention as Array.prototype.sort():

type Comparator<E> = (a: E, b: E) => number;
  • a negative value places a before b;
  • a positive value places a after b;
  • 0 makes the values equivalent while preserving their insertion order.

The comparator must define a consistent total ordering and must not return NaN. If it throws, the attempted insertion is not committed.

Properties

| Property | Type | Description | | --- | --- | --- | | size | number | Number of live entries. | | isEmpty | boolean | Whether the list contains no live entries. |

Methods

| Method | Result | Description | | --- | --- | --- | | insert(element) | SortedLinkedListNodeId | Inserts in sorted order and returns a new node ID. | | showHead() | E \| undefined | Reads the head element without removing it. | | showHead({returnEntry: true}) | SortedLinkedListEntry<E> \| undefined | Reads the head entry without removing it. | | showTail() | E \| undefined | Reads the tail element without removing it. | | showTail({returnEntry: true}) | SortedLinkedListEntry<E> \| undefined | Reads the tail entry without removing it. | | extractHead() | E \| undefined | Removes and returns the head element. | | extractHead({returnEntry: true}) | SortedLinkedListEntry<E> \| undefined | Removes and returns the head entry. | | extractTail() | E \| undefined | Removes and returns the tail element. | | extractTail({returnEntry: true}) | SortedLinkedListEntry<E> \| undefined | Removes and returns the tail entry. | | extractById(nodeId) | E \| undefined | Removes and returns the element identified by a live node ID. | | clear() | void | Removes all entries without reusing previous IDs. | | forEach(callback) | void | Visits entries in order; returning false stops traversal. | | [Symbol.iterator]() | Generator<SortedLinkedListEntry<E>> | Iterates from head to tail. |

When {returnEntry: true} is used, or when the list is iterated, an entry has this shape:

interface SortedLinkedListEntry<E> {
    readonly element: E;
    readonly nodeId: number;
}

Node IDs belong to one list instance. They increase monotonically, are not reused after extraction or clear(), and should be treated as opaque handles.

Complexity

Let n be the number of live entries and d the number of links traversed from the selected insertion anchor.

| Operation | Time | Notes | | --- | --- | --- | | Insert into an empty list, head, or tail | O(1) | Excluding comparator cost. | | Insert into the middle | O(d), worst O(n) | Starts near the last live insertion when possible. | | Read head, tail, size, or emptiness | O(1) | Direct metadata access. | | Extract head or tail | O(1) | Updates one boundary and adjacent link. | | Extract by node ID | Expected O(1) | Map lookup followed by constant-time unlinking. | | Full traversal | O(n) | Visits each reachable entry once. |

For middle insertion, the search starts from the most recently inserted live entry when possible. This can reduce d for clustered input, but the worst case remains O(n).

Space usage is O(n). Compared with a minimal linked list, each entry also has an ID and an index entry in the internal Map.

Choosing the right structure

Compared with a sorted array

A sorted array can locate an insertion position with binary search, but inserting or removing there shifts later elements. This linked list instead spends up to O(n) finding a middle position and then links the node in constant time. It is most effective when data often arrives near either boundary or the latest insertion.

Compared with a heap-based priority queue

A binary heap usually provides O(log n) insertion and head extraction, making it a better fit for large, randomly ordered queues that only consume the minimum or maximum. This list is a better fit when you also need full sorted traversal, stable equivalent ordering, or access to both boundaries.

Compared with a conventional linked list

A conventional linked list does not maintain ordering and normally needs a linear search to find an arbitrary value. This implementation maintains order on every insertion. Its optional ID lookup supports extractById() at the cost of additional memory.

Platform support

The published output targets ES2022 and uses no Node.js-specific API. It can run in modern Node.js, Bun, Deno, and browser projects whose runtime or bundler supports standard ESM and ES2022.

Development

npm ci
npm run check

License

MIT © 2026 Yurii Slobodeniuk