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 🙏

© 2025 – Pkg Stats / Ryan Hefner

frac-indexes

v1.1.1

Published

A library for generating fractional indexes for ordered lists

Readme

frac-indexes

A robust JavaScript library for generating lexicographically ordered fractional indexes. Perfect for maintaining order in lists when you need to insert items between existing ones without reindexing the entire list, or while supporting CRDT-style operations.

✨ Features

  • Production-Ready: Tested against edge cases involving small gaps, bulk insertions and move operations
  • Boundary-Safe: Stays within valid ranges and produces a moderate-sized index value with jitter
  • Bulk Operations: Efficient insertion and relocation of multiple items
  • Real-Time Friendly: Handles high-frequency collaborative editing
  • Zero Dependencies: Lightweight with no external dependencies
  • TypeScript Ready: Full type definitions included

📦 Installation

npm install frac-indexes

🚀 Quick Start

Node.js (Modern ES6+)

const { generateFractionalIndex, generateBulkIndexes } = require('frac-indexes');

// Create first item
const firstIndex = generateFractionalIndex(null, null);
// Returns (eg): 0.000548996

// Add item at the end  
const lastIndex = generateFractionalIndex(firstIndex, null);
// Returns (eg): 0.0016129989 

// Insert between two items
const middleIndex = generateFractionalIndex(firstIndex, lastIndex);
// Returns (based on first 2 examples): 0.001092958115464

// Bulk insert 5 items
const bulkIndexes = generateBulkIndexes(firstIndex, lastIndex, 5);

// Returns: [0.001114926762483, 0.001335277582793, 0.001494220983368, 0.001557755522828, 0.001587200051102]

Browser (ES5 Compatible)

<script src="node_modules/frac-indexes/src/es5-indexing.js"></script>
<script>
// Functions available under FractionalIndexing namespace
var firstIndex = FractionalIndexing.generateFractionalIndex(null, null);
var lastIndex = FractionalIndexing.generateFractionalIndex(firstIndex, null);
var middleIndex = FractionalIndexing.generateFractionalIndex(firstIndex, lastIndex);
</script>

Node.js (ES5 Compatible)

var fracIndexes = require('frac-indexes/src/es5-indexing');
var firstIndex = fracIndexes.generateFractionalIndex(null, null);

📚 API Reference

generateFractionalIndex(prevIndex, nextIndex)

Generates a single fractional index between two existing indexes.

Parameters:

  • prevIndex (string|null): The index before the desired position
  • nextIndex (string|null): The index after the desired position

Returns: (string) A new fractional index that will sort between the inputs

Example:

const index = generateFractionalIndex('0.001', '0.002');
// Returns (eg): 0.001392203389972

generateBulkIndexes(prevIndex, nextIndex, count)

Generates multiple fractional indexes between two existing indexes.

Parameters:

  • prevIndex (string|null): The index before the desired position
  • nextIndex (string|null): The index after the desired position
  • count (number): Number of indexes to generate

Returns: (string[]) An array of new fractional indexes

Example:

const indexes = generateBulkIndexes('0.001', '0.002', 3);
// Returns (eg): [ '0.001605493264275', '0.001827080243356', '0.001895877231710' ]

generateRelocationIndexes(targetPrevIndex, targetNextIndex, count, distributeEvenly)

Generates indexes for relocating multiple items to a new position.

Parameters:

  • targetPrevIndex (string|null): Index before the target position
  • targetNextIndex (string|null): Index after the target position
  • count (number): Number of items to relocate
  • distributeEvenly (boolean, optional): Whether to distribute items evenly (default: true)

Returns: (string[]) An array of new indexes for the relocated items

Example:

const newIndexes = generateRelocationIndexes('0.001', '0.003', 2, true);
// Returns evenly distributed indexes between 0.001 and 0.003

💡 Common Use Cases

Ordered Task Lists

const tasks = [
  { id: 1, index: generateFractionalIndex(null, null), title: "First task" },
  { id: 2, index: generateFractionalIndex(tasks[0].index, null), title: "Second task" }
];

// Insert between existing tasks
const newTaskIndex = generateFractionalIndex(tasks[0].index, tasks[1].index);
tasks.splice(1, 0, { id: 3, index: newTaskIndex, title: "Inserted task" });

Collaborative Editing

function insertMultipleItems(prevItem, nextItem, newItems) {
  const newIndexes = generateBulkIndexes(
    prevItem?.index || null, 
    nextItem?.index || null, 
    newItems.length
  );
  
  return newItems.map((item, i) => ({
    ...item,
    index: newIndexes[i]
  }));
}

Drag & Drop Reordering

function moveItems(itemsToMove, targetPosition) {
  const prevIndex = targetPosition.previous?.index || null;
  const nextIndex = targetPosition.next?.index || null;
  
  const newIndexes = generateRelocationIndexes(
    prevIndex, 
    nextIndex, 
    itemsToMove.length
  );
  
  return itemsToMove.map((item, i) => ({
    ...item,
    index: newIndexes[i]
  }));
}

🧪 Testing

# Run all tests (recommended)
npm test

# Run only basic functionality tests  
npm run test:basic

# Run only edge case/danger scenario tests
npm run test:danger

🔬 How It Works

The library generates high-precision decimal numbers as strings, ensuring:

  1. Lexicographical Ordering: String comparison matches numerical order
  2. Bounded Jitter: Random variation stays within safe mathematical bounds
  3. Precision Management: Uses 15+ decimal places to handle tiny gaps
  4. Boundary Protection: Multiple validation layers prevent range violations

Technical Details:

  • Uses IEEE 754 double precision with safety margins
  • Applies bounded randomization (max 25% of available gap)
  • Falls back to safe midpoints when gaps become microscopic
  • Maintains deterministic behavior under extreme conditions

🛡️ Production Safety Tests

This library has been tested against the following scenarios:

  • Small boundary Scenario: Ensure small gaps don't result in out of order indexes
  • Death by 1000 Cuts: Survives 15+ sequential subdivisions
  • Microscopic Gaps: Handles gaps down to floating-point precision limits
  • High Frequency: 100% reliability under 50+ concurrent operations

📄 License

MIT

👨‍💻 Author

Sai Prakash ([email protected])

🔗 Repository

https://github.com/SylonZero/frac-indexes