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

universal-data-structures

v1.0.1

Published

A universal JavaScript library providing extensible data structure classes (LinkedList, DoubleLinkedList, Tree, Graph) for use in any framework

Readme

Universal Data Structures

A comprehensive, framework-agnostic JavaScript library providing extensible data structure classes for use in any JavaScript environment including React, Vue, Angular, and Node.js.

npm version License: MIT

🚀 Features

  • Framework Agnostic: Works with React, Vue, Angular, and vanilla JavaScript
  • Extensible Classes: All classes are designed to be extended with custom functionality
  • TypeScript Support: Full TypeScript declarations included
  • Multiple Module Formats: ESM, CommonJS, UMD, and IIFE builds
  • Comprehensive API: Rich set of methods for each data structure
  • Optimized Performance: Efficient implementations with optimal time complexity
  • Well Documented: Complete API documentation with examples

🔧 Extension Examples Included

  • UniqueLinkedList: Prevents duplicate entries
  • BoundedLinkedList: Size-limited list with events
  • LRUCache: Least Recently Used cache using DoubleLinkedList
  • FileSystemTree: Hierarchical file system implementation
  • SocialNetworkGraph: Friend suggestions and connection paths
  • Factory Patterns: Create data structures dynamically
  • Event Mixins: Add event capabilities to any structure

All examples show real-world use cases you can adapt for your specific needs!

📦 Installation

npm install universal-data-structures
yarn add universal-data-structures
pnpm add universal-data-structures

🏁 Quick Start

ES Modules (Recommended)

import { LinkedList, Tree, Graph } from 'universal-data-structures';

const list = new LinkedList();
list.append('item1').append('item2').append('item3');
console.log(list.toArray()); // ['item1', 'item2', 'item3']

CommonJS

const { LinkedList, Tree, Graph } = require('universal-data-structures');

const tree = new Tree('root');
tree.addChild('root', 'child1');
tree.addChild('root', 'child2');

UMD (Browser)

<script src="node_modules/universal-data-structures/dist/index.umd.js"></script>
<script>
  const { LinkedList } = UniversalDataStructures;
  const list = new LinkedList();
</script>

📚 Data Structures

🔗 LinkedList

A singly linked list implementation with comprehensive methods.

Basic Usage

import { LinkedList } from 'universal-data-structures';

const list = new LinkedList();

// Adding elements
list.append('first')
    .append('second')
    .prepend('beginning');

// Accessing elements
console.log(list.get(0)); // 'beginning'
console.log(list.indexOf('second')); // 2

// Removing elements
list.remove('first');
list.removeAt(0);

// Utility methods
console.log(list.length()); // 1
console.log(list.toArray()); // ['second']

API Reference

| Method | Description | Time Complexity | |--------|-------------|-----------------| | append(data) | Add element to the end | O(1) | | prepend(data) | Add element to the beginning | O(1) | | insertAt(index, data) | Insert element at specific index | O(n) | | remove(data) | Remove first occurrence of data | O(n) | | removeAt(index) | Remove element at index | O(n) | | get(index) | Get element at index | O(n) | | indexOf(data) | Find index of element | O(n) | | contains(data) | Check if element exists | O(n) | | length() | Get size of list | O(1) | | isEmpty() | Check if list is empty | O(1) | | clear() | Remove all elements | O(1) | | reverse() | Reverse the list | O(n) | | toArray() | Convert to array | O(n) |

↔️ DoubleLinkedList

A doubly linked list with bidirectional traversal capabilities.

Basic Usage

import { DoubleLinkedList } from 'universal-data-structures';

const dlist = new DoubleLinkedList();

// Adding elements
dlist.append('middle')
     .prepend('first')
     .append('last');

// Bidirectional access
console.log(dlist.getFirst()); // 'first'
console.log(dlist.getLast()); // 'last'

// Efficient operations at both ends
dlist.removeFirst();
dlist.removeLast();

// Backward traversal
console.log(dlist.toArrayReverse()); // ['middle']

// Iterate backwards
for (const item of dlist.reverseIterator()) {
  console.log(item);
}

API Reference

All LinkedList methods plus:

| Method | Description | Time Complexity | |--------|-------------|-----------------| | removeFirst() | Remove first element | O(1) | | removeLast() | Remove last element | O(1) | | getFirst() | Get first element | O(1) | | getLast() | Get last element | O(1) | | lastIndexOf(data) | Find last index of element | O(n) | | toArrayReverse() | Convert to array in reverse order | O(n) | | reverseIterator() | Iterator for backward traversal | O(1) |

🌳 Tree

A general tree implementation supporting multiple children per node.

Basic Usage

import { Tree } from 'universal-data-structures';

const tree = new Tree('root');

// Building the tree
tree.addChild('root', 'child1');
tree.addChild('root', 'child2');
tree.addChild('child1', 'grandchild1');
tree.addChild('child1', 'grandchild2');

// Traversals
console.log(tree.traverseDepthFirst());  // ['root', 'child1', 'grandchild1', 'grandchild2', 'child2']
console.log(tree.traverseBreadthFirst()); // ['root', 'child1', 'child2', 'grandchild1', 'grandchild2']

// Tree analysis
console.log(tree.getHeight()); // 2
console.log(tree.getLeaves()); // ['grandchild1', 'grandchild2', 'child2']
console.log(tree.getNodesAtLevel(1)); // ['child1', 'child2']

API Reference

| Method | Description | Time Complexity | |--------|-------------|-----------------| | setRoot(data) | Set tree root | O(1) | | addChild(parentData, childData) | Add child to parent | O(n) | | remove(data) | Remove node and descendants | O(n) | | find(data) | Find node with data | O(n) | | traverseDepthFirst() | DFS traversal | O(n) | | traverseBreadthFirst() | BFS traversal | O(n) | | getHeight() | Get tree height | O(n) | | getLeaves() | Get all leaf nodes | O(n) | | getNodesAtLevel(level) | Get nodes at specific level | O(n) |

🌲 BinaryTree

A binary tree implementation with specialized traversal methods.

Basic Usage

import { BinaryTree, BinaryTreeNode } from 'universal-data-structures';

const binaryTree = new BinaryTree('root');

// Manual tree construction
binaryTree.root.left = new BinaryTreeNode('left');
binaryTree.root.right = new BinaryTreeNode('right');
binaryTree.root.left.left = new BinaryTreeNode('left-left');

// Traversals
console.log(binaryTree.inOrder());    // ['left-left', 'left', 'root', 'right']
console.log(binaryTree.preOrder());   // ['root', 'left', 'left-left', 'right']
console.log(binaryTree.postOrder());  // ['left-left', 'left', 'right', 'root']
console.log(binaryTree.levelOrder()); // ['root', 'left', 'right', 'left-left']

📊 Graph

A versatile graph implementation supporting both directed and undirected graphs.

Basic Usage

import { Graph } from 'universal-data-structures';

// Create undirected graph
const graph = new Graph(false);

// Add vertices and edges
graph.addVertex('A')
     .addVertex('B')
     .addVertex('C')
     .addEdge('A', 'B', 2)
     .addEdge('B', 'C', 3)
     .addEdge('C', 'A', 1);

// Traversals
console.log(graph.depthFirstSearch('A'));    // ['A', 'B', 'C']
console.log(graph.breadthFirstSearch('A'));  // ['A', 'B', 'C']

// Shortest path
const result = graph.dijkstra('A', 'C');
console.log(result.path);     // ['A', 'C']
console.log(result.distance); // 1

// Graph analysis
console.log(graph.isConnected()); // true
console.log(graph.hasCycle());    // true

API Reference

| Method | Description | Time Complexity | |--------|-------------|-----------------| | addVertex(vertex) | Add vertex | O(1) | | addEdge(from, to, weight) | Add weighted edge | O(1) | | removeVertex(vertex) | Remove vertex and edges | O(V + E) | | removeEdge(from, to) | Remove edge | O(1) | | hasEdge(from, to) | Check if edge exists | O(1) | | getNeighbors(vertex) | Get adjacent vertices | O(1) | | depthFirstSearch(start) | DFS traversal | O(V + E) | | breadthFirstSearch(start) | BFS traversal | O(V + E) | | dijkstra(start, end) | Shortest path | O((V + E) log V) | | hasCycle() | Detect cycles | O(V + E) | | isConnected() | Check connectivity | O(V + E) |

🔧 Framework Integration

React

import React, { useState, useEffect } from 'react';
import { LinkedList } from 'universal-data-structures';

// Custom hook for LinkedList
function useLinkedList(initialItems = []) {
  const [list] = useState(() => {
    const ll = new LinkedList();
    initialItems.forEach(item => ll.append(item));
    return ll;
  });
  
  const [items, setItems] = useState(list.toArray());

  const refresh = () => setItems(list.toArray());

  const append = (item) => {
    list.append(item);
    refresh();
  };

  return { list, items, append, refresh };
}

function TodoList() {
  const { items, append } = useLinkedList(['Initial item']);
  const [newItem, setNewItem] = useState('');

  const handleAdd = () => {
    if (newItem.trim()) {
      append(newItem);
      setNewItem('');
    }
  };

  return (
    <div>
      <input 
        value={newItem} 
        onChange={(e) => setNewItem(e.target.value)}
        onKeyPress={(e) => e.key === 'Enter' && handleAdd()}
      />
      <button onClick={handleAdd}>Add</button>
      <ul>
        {items.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

Vue 3 (Composition API)

<template>
  <div>
    <input 
      v-model="newItem" 
      @keyup.enter="addItem" 
      placeholder="Add item"
    />
    <button @click="addItem">Add</button>
    <ul>
      <li v-for="item in items" :key="item">{{ item }}</li>
    </ul>
  </div>
</template>

<script>
import { ref, computed } from 'vue';
import { LinkedList } from 'universal-data-structures';

// Composable for LinkedList
function useLinkedList(initialItems = []) {
  const list = new LinkedList();
  initialItems.forEach(item => list.append(item));
  
  const items = ref(list.toArray());

  const refresh = () => {
    items.value = list.toArray();
  };

  const append = (item) => {
    list.append(item);
    refresh();
  };

  return { list, items, append };
}

export default {
  setup() {
    const { items, append } = useLinkedList(['Initial item']);
    const newItem = ref('');

    const addItem = () => {
      if (newItem.value.trim()) {
        append(newItem.value);
        newItem.value = '';
      }
    };

    return {
      items,
      newItem,
      addItem
    };
  }
};
</script>

Angular

import { Injectable, Component } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { LinkedList } from 'universal-data-structures';

@Injectable({
  providedIn: 'root'
})
export class DataStructureService {
  private list = new LinkedList();
  private listSubject = new BehaviorSubject<any[]>([]);
  
  public items$ = this.listSubject.asObservable();

  addItem(item: any): void {
    this.list.append(item);
    this.listSubject.next(this.list.toArray());
  }

  removeItem(item: any): void {
    this.list.remove(item);
    this.listSubject.next(this.list.toArray());
  }
}

@Component({
  selector: 'app-todo',
  template: `
    <div>
      <input [(ngModel)]="newItem" (keyup.enter)="addItem()" />
      <button (click)="addItem()">Add</button>
      <ul>
        <li *ngFor="let item of items$ | async">{{ item }}</li>
      </ul>
    </div>
  `
})
export class TodoComponent {
  newItem = '';
  items$ = this.dataService.items$;

  constructor(private dataService: DataStructureService) {}

  addItem(): void {
    if (this.newItem.trim()) {
      this.dataService.addItem(this.newItem);
      this.newItem = '';
    }
  }
}

🔄 Extension Patterns

All data structures in this library are designed to be easily extensible. Here are comprehensive examples showing different extension patterns for real-world use cases:

🔗 Extending LinkedList

Basic Extension - Unique List

import { LinkedList } from 'universal-data-structures';

class UniqueLinkedList extends LinkedList {
  append(data) {
    if (!this.contains(data)) {
      return super.append(data);
    }
    return this;
  }

  appendUnique(data) {
    return this.append(data);
  }

  getMiddle() {
    if (this.isEmpty()) return null;
    
    let slow = this.head;
    let fast = this.head;
    
    while (fast && fast.next) {
      slow = slow.next;
      fast = fast.next.next;
    }
    
    return slow.data;
  }
}

const uniqueList = new UniqueLinkedList();
uniqueList.append('item1')
          .append('item2')
          .append('item1'); // Won't be added again

console.log(uniqueList.toArray()); // ['item1', 'item2']
console.log(uniqueList.getMiddle()); // 'item1' or 'item2' depending on implementation

Advanced Extension - Bounded List with Events

class BoundedLinkedList extends LinkedList {
  constructor(maxSize = 10) {
    super();
    this.maxSize = maxSize;
    this.listeners = new Map();
  }

  // Event system
  on(event, callback) {
    if (!this.listeners.has(event)) {
      this.listeners.set(event, []);
    }
    this.listeners.get(event).push(callback);
    return this;
  }

  emit(event, data) {
    const callbacks = this.listeners.get(event) || [];
    callbacks.forEach(callback => callback(data));
  }

  append(data) {
    if (this.size >= this.maxSize) {
      this.emit('overflow', { item: data, currentSize: this.size });
      // Remove oldest item to make room
      const removed = this.removeAt(0);
      this.emit('evicted', { item: removed });
    }
    
    super.append(data);
    this.emit('added', { item: data, newSize: this.size });
    return this;
  }

  // Batch operations
  appendBatch(items) {
    const results = [];
    for (const item of items) {
      try {
        this.append(item);
        results.push({ item, success: true });
      } catch (error) {
        results.push({ item, success: false, error: error.message });
      }
    }
    return results;
  }

  // Statistical methods
  getStats() {
    return {
      size: this.size,
      maxSize: this.maxSize,
      utilizationPercent: (this.size / this.maxSize * 100).toFixed(2),
      isEmpty: this.isEmpty(),
      isFull: this.size >= this.maxSize
    };
  }
}

// Usage Example
const boundedList = new BoundedLinkedList(3);

boundedList
  .on('overflow', (data) => console.log('List overflow!', data))
  .on('evicted', (data) => console.log('Item evicted:', data))
  .on('added', (data) => console.log('Item added:', data));

boundedList.appendBatch(['a', 'b', 'c', 'd']); // 'd' will cause overflow

↔️ Extending DoubleLinkedList

LRU Cache Implementation

import { DoubleLinkedList, DoubleListNode } from 'universal-data-structures';

class LRUCache extends DoubleLinkedList {
  constructor(capacity = 100) {
    super();
    this.capacity = capacity;
    this.cache = new Map(); // key -> node mapping
  }

  get(key) {
    if (this.cache.has(key)) {
      const node = this.cache.get(key);
      // Move to front (most recently used)
      this.moveToFront(node);
      return node.data.value;
    }
    return null;
  }

  put(key, value) {
    if (this.cache.has(key)) {
      // Update existing
      const node = this.cache.get(key);
      node.data.value = value;
      this.moveToFront(node);
    } else {
      // Add new
      if (this.size >= this.capacity) {
        // Remove least recently used (tail)
        const lru = this.tail;
        this.cache.delete(lru.data.key);
        this.removeLast();
      }

      const data = { key, value };
      this.prepend(data);
      this.cache.set(key, this.head);
    }
  }

  moveToFront(node) {
    if (node === this.head) return; // Already at front

    // Remove from current position
    if (node.prev) node.prev.next = node.next;
    if (node.next) node.next.prev = node.prev;
    if (node === this.tail) this.tail = node.prev;

    // Add to front
    node.prev = null;
    node.next = this.head;
    if (this.head) this.head.prev = node;
    this.head = node;
    if (!this.tail) this.tail = node;
  }
}

// Usage
const cache = new LRUCache(3);
cache.put('a', 1);
cache.put('b', 2);
cache.put('c', 3);
cache.put('d', 4); // 'a' gets evicted
console.log(cache.get('b')); // 2, moves 'b' to front

🌳 Extending Tree

File System Tree

import { Tree, TreeNode } from 'universal-data-structures';

class FileSystemTree extends Tree {
  constructor() {
    super('/'); // Root directory
    this.nodeMap = new Map();
    this.nodeMap.set('/', this.root);
  }

  createFile(path, content = '') {
    const parts = path.split('/').filter(p => p);
    let currentPath = '';
    let currentNode = this.root;

    // Create intermediate directories
    for (let i = 0; i < parts.length - 1; i++) {
      currentPath += '/' + parts[i];
      if (!this.nodeMap.has(currentPath)) {
        const dirNode = currentNode.addChild({
          name: parts[i],
          type: 'directory',
          path: currentPath
        });
        this.nodeMap.set(currentPath, dirNode);
        this.size++;
      }
      currentNode = this.nodeMap.get(currentPath);
    }

    // Create file
    const fileName = parts[parts.length - 1];
    const filePath = currentPath + '/' + fileName;
    
    const fileNode = currentNode.addChild({
      name: fileName,
      type: 'file',
      path: filePath,
      content: content,
      size: content.length,
      created: new Date()
    });

    this.nodeMap.set(filePath, fileNode);
    this.size++;
    return fileNode;
  }

  readFile(path) {
    const node = this.nodeMap.get(path);
    if (!node || node.data.type !== 'file') {
      throw new Error(`File not found: ${path}`);
    }
    return node.data.content;
  }

  listDirectory(path = '/') {
    const node = this.nodeMap.get(path);
    if (!node) throw new Error(`Directory not found: ${path}`);

    return node.children.map(child => ({
      name: child.data.name,
      type: child.data.type,
      size: child.data.size || 0
    }));
  }

  findFiles(pattern) {
    const results = [];
    const regex = new RegExp(pattern);

    for (const [path, node] of this.nodeMap) {
      if (node.data.type === 'file' && regex.test(node.data.name)) {
        results.push({ path, name: node.data.name });
      }
    }
    return results;
  }
}

// Usage
const fs = new FileSystemTree();
fs.createFile('/documents/readme.txt', 'Hello World');
fs.createFile('/documents/projects/app.js', 'console.log("Hello");');
console.log(fs.listDirectory('/documents'));
console.log(fs.findFiles('.*\\.js$')); // Find all JS files

📊 Extending Graph - Social Network

Social Network Implementation

import { Graph } from 'universal-data-structures';

class SocialNetworkGraph extends Graph {
  constructor() {
    super(false); // Undirected for mutual friendships
    this.users = new Map();
  }

  addUser(userId, userData) {
    this.addVertex(userId);
    this.users.set(userId, {
      id: userId,
      ...userData,
      joinedAt: new Date(),
      friends: new Set()
    });
    return this;
  }

  addFriendship(user1, user2, strength = 1) {
    this.addEdge(user1, user2, strength);
    this.users.get(user1)?.friends.add(user2);
    this.users.get(user2)?.friends.add(user1);
    return this;
  }

  getMutualFriends(user1, user2) {
    const friends1 = this.users.get(user1)?.friends || new Set();
    const friends2 = this.users.get(user2)?.friends || new Set();
    
    return Array.from(friends1).filter(friend => friends2.has(friend));
  }

  getFriendSuggestions(userId, limit = 5) {
    const user = this.users.get(userId);
    if (!user) return [];

    const suggestions = new Map();
    
    for (const friendId of user.friends) {
      const friendsFriends = this.users.get(friendId)?.friends || new Set();
      
      for (const suggestion of friendsFriends) {
        if (suggestion !== userId && !user.friends.has(suggestion)) {
          suggestions.set(suggestion, (suggestions.get(suggestion) || 0) + 1);
        }
      }
    }

    return Array.from(suggestions.entries())
      .sort((a, b) => b[1] - a[1])
      .slice(0, limit)
      .map(([userId, mutualCount]) => ({
        userId,
        mutualFriendsCount: mutualCount,
        userData: this.users.get(userId)
      }));
  }

  getConnectionPath(user1, user2) {
    const result = this.dijkstra(user1, user2);
    return {
      path: result.path,
      degreeOfSeparation: result.path.length - 1
    };
  }
}

// Usage
const socialNet = new SocialNetworkGraph();
socialNet
  .addUser('alice', { name: 'Alice Smith', age: 28 })
  .addUser('bob', { name: 'Bob Johnson', age: 32 })
  .addUser('charlie', { name: 'Charlie Brown', age: 25 })
  .addFriendship('alice', 'bob')
  .addFriendship('bob', 'charlie');

console.log(socialNet.getFriendSuggestions('alice'));
console.log(socialNet.getConnectionPath('alice', 'charlie'));

🔧 Advanced Patterns

Factory Pattern for Data Structures

class DataStructureFactory {
  static create(type, options = {}) {
    switch (type) {
      case 'uniqueList':
        return new UniqueLinkedList();
      case 'boundedList':
        return new BoundedLinkedList(options.maxSize);
      case 'lruCache':
        return new LRUCache(options.capacity);
      case 'fileSystem':
        return new FileSystemTree();
      case 'socialNetwork':
        return new SocialNetworkGraph();
      default:
        throw new Error(`Unknown type: ${type}`);
    }
  }
}

// Usage
const cache = DataStructureFactory.create('lruCache', { capacity: 50 });
const fileSystem = DataStructureFactory.create('fileSystem');

Mixin Pattern for Shared Functionality

const EventEmitterMixin = {
  initEvents() {
    this._listeners = new Map();
  },

  on(event, callback) {
    if (!this._listeners.has(event)) {
      this._listeners.set(event, []);
    }
    this._listeners.get(event).push(callback);
    return this;
  },

  emit(event, data) {
    (this._listeners.get(event) || []).forEach(cb => cb(data));
  }
};

// Apply to any data structure
class EventLinkedList extends LinkedList {
  constructor() {
    super();
    this.initEvents();
  }

  append(data) {
    super.append(data);
    this.emit('itemAdded', { item: data, size: this.size });
    return this;
  }
}

Object.assign(EventLinkedList.prototype, EventEmitterMixin);

These examples demonstrate the flexibility of the Universal Data Structures library. Each base class provides a solid foundation that you can extend with domain-specific functionality while maintaining performance and core behavior.

Extending Graph with Custom Algorithms

import { Graph } from 'universal-data-structures';

class AdvancedGraph extends Graph {
  constructor(isDirected = false) {
    super(isDirected);
  }

  // Kruskal's algorithm for minimum spanning tree
  minimumSpanningTree() {
    if (this.isDirected) {
      throw new Error('MST is only for undirected graphs');
    }

    const edges = this.getAllEdges()
      .sort((a, b) => a.weight - b.weight);
    
    const parent = new Map();
    const rank = new Map();
    
    // Initialize Union-Find
    for (const vertex of this.getVertices()) {
      parent.set(vertex, vertex);
      rank.set(vertex, 0);
    }

    const find = (vertex) => {
      if (parent.get(vertex) !== vertex) {
        parent.set(vertex, find(parent.get(vertex)));
      }
      return parent.get(vertex);
    };

    const union = (a, b) => {
      const rootA = find(a);
      const rootB = find(b);
      
      if (rootA !== rootB) {
        if (rank.get(rootA) < rank.get(rootB)) {
          parent.set(rootA, rootB);
        } else if (rank.get(rootA) > rank.get(rootB)) {
          parent.set(rootB, rootA);
        } else {
          parent.set(rootB, rootA);
          rank.set(rootA, rank.get(rootA) + 1);
        }
        return true;
      }
      return false;
    };

    const mst = [];
    for (const edge of edges) {
      if (union(edge.from, edge.to)) {
        mst.push(edge);
        if (mst.length === this.getVertexCount() - 1) {
          break;
        }
      }
    }

    return mst;
  }
}

🎯 Use Cases

Data Processing Pipeline

import { LinkedList, Tree, Graph } from 'universal-data-structures';

class DataPipeline {
  constructor() {
    this.stages = new LinkedList();
    this.dependencies = new Graph(true); // directed graph
  }

  addStage(stageName, processor) {
    this.stages.append({ name: stageName, processor });
    this.dependencies.addVertex(stageName);
    return this;
  }

  addDependency(from, to) {
    this.dependencies.addEdge(from, to);
    return this;
  }

  execute(data) {
    const executionOrder = this.dependencies.topologicalSort();
    let result = data;

    for (const stageName of executionOrder) {
      const stage = this.stages.toArray()
        .find(s => s.name === stageName);
      
      if (stage) {
        result = stage.processor(result);
      }
    }

    return result;
  }
}

// Usage
const pipeline = new DataPipeline();
pipeline
  .addStage('validate', data => ({ ...data, validated: true }))
  .addStage('transform', data => ({ ...data, transformed: true }))
  .addStage('save', data => ({ ...data, saved: true }))
  .addDependency('validate', 'transform')
  .addDependency('transform', 'save');

const result = pipeline.execute({ input: 'data' });

Navigation System

import { Graph } from 'universal-data-structures';

class NavigationSystem {
  constructor() {
    this.map = new Graph(false); // undirected for roads
  }

  addLocation(name) {
    this.map.addVertex(name);
    return this;
  }

  addRoad(from, to, distance) {
    this.map.addEdge(from, to, distance);
    return this;
  }

  findRoute(start, destination) {
    const result = this.map.dijkstra(start, destination);
    return {
      path: result.path,
      totalDistance: result.distance,
      directions: this.generateDirections(result.path)
    };
  }

  generateDirections(path) {
    const directions = [];
    for (let i = 0; i < path.length - 1; i++) {
      const from = path[i];
      const to = path[i + 1];
      const distance = this.map.getEdgeWeight(from, to);
      directions.push(`Go from ${from} to ${to} (${distance} km)`);
    }
    return directions;
  }
}

🧪 Testing

The library includes comprehensive tests. Run them with:

npm test

Example test:

import { LinkedList } from 'universal-data-structures';

describe('LinkedList', () => {
  test('should append and retrieve elements', () => {
    const list = new LinkedList();
    list.append('first').append('second');
    
    expect(list.length()).toBe(2);
    expect(list.get(0)).toBe('first');
    expect(list.get(1)).toBe('second');
  });

  test('should handle extension properly', () => {
    class ExtendedList extends LinkedList {
      appendIfNotExists(item) {
        if (!this.contains(item)) {
          this.append(item);
        }
        return this;
      }
    }

    const list = new ExtendedList();
    list.appendIfNotExists('item')
        .appendIfNotExists('item'); // shouldn't add duplicate

    expect(list.length()).toBe(1);
  });
});

📖 API Documentation

TypeScript Support

The library includes complete TypeScript definitions:

import { LinkedList, Tree, Graph } from 'universal-data-structures';

// Generic types supported
const stringList = new LinkedList<string>();
const numberTree = new Tree<number>(42);
const userGraph = new Graph<User>(false);

// Type-safe operations
stringList.append('hello'); // ✅ OK
stringList.append(123);     // ❌ Type error

interface User {
  id: number;
  name: string;
}

userGraph.addVertex({ id: 1, name: 'Alice' });

Performance Characteristics

| Data Structure | Access | Search | Insertion | Deletion | Space | |----------------|--------|--------|-----------|----------|-------| | LinkedList | O(n) | O(n) | O(1) at head/tail | O(n) | O(n) | | DoubleLinkedList | O(n) | O(n) | O(1) at ends | O(1) at ends | O(n) | | Tree | O(h) | O(n) | O(1) with parent ref | O(1) with ref | O(n) | | Graph | O(1) | O(V+E) | O(1) | O(V+E) | O(V+E) |

Where:

  • n = number of elements
  • h = height of tree
  • V = number of vertices
  • E = number of edges

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🆓 Free to Use

This library is completely free and open source under the MIT License, which means:

Commercial Use: Use in commercial projects without restrictions
Modification: Modify and customize the code for your needs
Distribution: Distribute the original or modified versions
Private Use: Use in private/internal projects
No Attribution Required: While appreciated, not legally required
No Warranty: Provided "as-is" without warranty

MIT License Summary

MIT License

Copyright (c) 2024 Universal Data Structures

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND...

You can use this library in any project - personal, commercial, or open source - without any licensing fees or restrictions!

🔗 Links

📊 Bundle Size

| Format | Size (gzipped) | |--------|----------------| | ESM | ~8KB | | CommonJS | ~8KB | | UMD | ~10KB | | IIFE | ~10KB |

🌟 Why Choose Universal Data Structures?

  • Framework Agnostic: Use anywhere JavaScript runs
  • TypeScript Ready: Full type safety out of the box
  • Extensible Design: Easy to extend and customize
  • Performance Optimized: Efficient algorithms and data structures
  • Well Tested: Comprehensive test suite
  • Production Ready: Used in production applications
  • Active Maintenance: Regular updates and bug fixes
  • Great Documentation: Complete API docs with examples

Made with ❤️ for the JavaScript community