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

order-with-group

v0.1.4

Published

A lightweight, zero-dependency TypeScript utility library for managing hierarchical ordered items with grouping support. Navigate trees, traverse siblings, and walk nested structures with a simple, predictable API.

Downloads

283

Readme

order-with-group

A lightweight, zero-dependency TypeScript utility library for managing hierarchical ordered items with grouping support. Navigate trees, traverse siblings, and walk nested structures with a simple, predictable API.

Features

  • Zero dependencies — tiny footprint, nothing to audit.
  • Generic IDs — works with number, string, UUID, or any comparable type.
  • Depth-first traversalgetNextItem visits children before siblings, matching intuitive tree-walk expectations.
  • Full TypeScript support — strict types, no any anywhere.
  • Well-tested — 90+ tests covering flat lists, nested trees, and edge cases.

Demo

Try it live: order-with-group.insanasia.id

Installation

npm install order-with-group

Data Structure

Every item follows this shape:

type OWG_Item<T> = {
  id: T;              // unique identifier (number, string, UUID, etc.)
  order: number;      // sort position among siblings
  title?: string;     // optional human-readable label
  parentId?: T | null; // null = root-level item
};

Items are stored in a flat array — no nesting. The tree structure is defined entirely by parentId references.

Quick Example

import { getItem, getNextItem, getSiblings, isFirst, isLast } from 'order-with-group';

const menu = [
  { id: 1, order: 1, title: 'Soups',  parentId: null },
  { id: 2, order: 2, title: 'Mains',  parentId: null },
  { id: 3, order: 1, title: 'Tomato', parentId: 1 },
  { id: 4, order: 2, title: 'Chicken', parentId: 1 },
];

// Depth-first walk
let item = getItem(menu, 1); // Soups
while (item) {
  console.log(item.title);
  item = getNextItem(menu, item.id);
}
// Soups → Tomato → Chicken → Mains

// Sibling queries
getSiblings(menu, 3); // [Tomato, Chicken] — both under Soups
isFirst(menu, 3);     // true  — Tomato is first soup
isLast(menu, 4);      // true  — Chicken is last soup

API Reference

getItem<T>(items, id)

Finds and returns an item by its id. Returns undefined if not found.

function getItem<T>(items: OWG_Item<T>[], id: T): OWG_Item<T> | undefined

getSiblings<T>(items, currentId)

Returns all items that share the same parentId as the given item, sorted by order. Includes the item itself.

function getSiblings<T>(items: OWG_Item<T>[], currentId: T): OWG_Item<T>[]

getFirstChildren<T>(items, currentId)

Returns the first child (lowest order) of the given item, or undefined if it has no children.

function getFirstChildren<T>(items: OWG_Item<T>[], currentId: T): OWG_Item<T> | undefined

getFirstChildrenOrSelf<T>(items, currentId)

Returns the first child if one exists, otherwise returns the item itself. Useful for "drill down or stay" logic.

function getFirstChildrenOrSelf<T>(items: OWG_Item<T>[], currentId: T): OWG_Item<T> | undefined

getNextItem<T>(items, currentId)

Returns the next item in a depth-first pre-order traversal:

  1. First child (if any)
  2. Next sibling (or its first descendant)
  3. Parent's next sibling (walking up the tree)
  4. undefined if it's the very last item
function getNextItem<T>(items: OWG_Item<T>[], currentId: T): OWG_Item<T> | undefined

isFirst<T>(items, currentId, amongSiblings?)

Checks if the item is first. By default, checks among siblings only. Pass false as the third argument to check against the raw array (first element).

function isFirst<T>(items: OWG_Item<T>[], currentId: T, amongSiblings?: boolean): boolean

isFirstInSiblings<T>(items, currentId)

Same as isFirst with amongSiblings = true. Checks if the item has the lowest order among its siblings.

function isFirstInSiblings<T>(items: OWG_Item<T>[], currentId: T): boolean

isLast<T>(items, currentId, amongSiblings?)

Checks if the item is last. By default, checks among siblings only. Pass false as the third argument to check against the raw array (last element).

function isLast<T>(items: OWG_Item<T>[], currentId: T, amongSiblings?: boolean): boolean

isLastInSiblings<T>(items, currentId)

Same as isLast with amongSiblings = true. Checks if the item has the highest order among its siblings.

function isLastInSiblings<T>(items: OWG_Item<T>[], currentId: T): boolean

hasAncestor<T>(items, descendantId, ancestorId)

Returns true if ancestorId is anywhere in the parent chain of descendantId. Walks the full ancestry, not just direct parent.

function hasAncestor<T>(items: OWG_Item<T>[], descendantId: T, ancestorId: T): boolean

More Examples

See examples.md for real-world usage scenarios including:

  • Flat list navigation (production process steps)
  • Nested category traversal (recipe menus)
  • Deeply nested HACCP checklists
  • Breadcrumb / ancestry checks
  • String IDs (UUID / slug)

License

MIT