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 traversal —
getNextItemvisits children before siblings, matching intuitive tree-walk expectations. - Full TypeScript support — strict types, no
anyanywhere. - 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-groupData 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 soupAPI 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> | undefinedgetSiblings<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> | undefinedgetFirstChildrenOrSelf<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> | undefinedgetNextItem<T>(items, currentId)
Returns the next item in a depth-first pre-order traversal:
- First child (if any)
- Next sibling (or its first descendant)
- Parent's next sibling (walking up the tree)
undefinedif it's the very last item
function getNextItem<T>(items: OWG_Item<T>[], currentId: T): OWG_Item<T> | undefinedisFirst<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): booleanisFirstInSiblings<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): booleanisLast<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): booleanisLastInSiblings<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): booleanhasAncestor<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): booleanMore 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
