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

ordercraft

v0.1.0

Published

Correct mixed-type sorting, natural and locale ordering, indexed search, ranking, and fuzzy matching. Zero runtime dependencies.

Downloads

32

Readme

Ordercraft

Deterministic sorting and search for JavaScript data that refuses to stay one type.

npm version npm downloads license Node.js

Ordercraft gives every value a stable, explicit place in the order. It handles mixed columns containing numbers, strings, null, undefined, bigint, dates, booleans, NaN, and very large numeric text without pair-dependent coercion. It also includes natural and locale-aware strings, exact decimal comparison, stable multi-column sorting, radix sorting, binary search, indexes, top-k selection, ranking, and Unicode fuzzy matching.

Install

npm install ordercraft

Ordercraft has zero runtime dependencies. It ships ESM and CommonJS entry points, TypeScript declarations, and tree-shakeable subpaths. Node.js 22 or newer is supported; browser bundles work in modern ES2022 environments.

The mixed-value problem

This comparator is tempting:

function compare(a, b) {
  if (typeof a === 'number' && typeof b === 'number') return a - b;
  return String(a ?? '').localeCompare(String(b ?? ''), undefined, { numeric: true });
}

It chooses a comparison rule from the pair of values. A mixed column can then contain a cycle: a ≤ b, b ≤ c, and a > c. Array.prototype.sort has no defined result for an intransitive comparator, so input order and engine version can change the rendered order.

Ordercraft classifies each value once. The default order is:

boolean < number < bigint < Date < string < null < undefined

Numbers come before strings by product decision. Numeric-looking strings remain strings unless coercion is explicitly requested. NaN and invalid dates have a deterministic position, signed zero is handled deliberately, and canonical ties make equal spellings reproducible.

Quick start

import { createComparator, sort } from 'ordercraft';

const compare = createComparator({ strings: 'natural' });
const values = [1e21, '2', 10, 'file10', 'file2', null, undefined, 3];

const ordered = sort(values, { compare });
console.log(ordered);
// [3, 10, 1e+21, '2', 'file2', 'file10', null, undefined]

Pass the comparator directly to native sorting when you already have an array:

import { createComparator } from 'ordercraft';

const compare = createComparator({ strings: 'natural' });
const rows = [
  { label: 'file10', value: 10 },
  { label: 'file2', value: 2 },
  { label: 'file1', value: '1' },
];

rows.sort((a, b) => compare(a.value, b.value));

For records, selectors run once per row and prepared keys are reused during the sort:

import { orderBy, createOrder } from 'ordercraft';

const natural = createOrder({ strings: 'natural' });
const ordered = orderBy(rows, [
  { select: row => row.value },
  { select: row => row.label, policy: natural },
]);

Ordering policies

createOrder(options) returns a policy with compare, prepare, and comparePrepared. Use the policy when sorting repeatedly, building an index, or composing criteria.

| Option | Values | Default | Meaning | | --- | --- | --- | --- | | strings | ordinal, codePoint, natural, locale | ordinal | String comparison model | | numericStrings | preserve, coerce | preserve | Whether complete finite decimal/scientific strings become numbers | | ties | canonical, equivalent | canonical | Refine or retain equivalent representations | | missing | first, last | last | Placement of null and undefined | | direction | asc, desc | asc | Direction for defined values |

Coercion is opt-in and uses a complete ASCII decimal/scientific grammar:

import { createComparator } from 'ordercraft';

const numericText = createComparator({ numericStrings: 'coerce', ties: 'equivalent' });
numericText('2e1', 20);       // 0
numericText('2px', 20);       // positive: it remains text
numericText('1e9999', 20);    // positive: overflow remains text

When decimal strings must retain precision beyond Number, use the exact decimal comparator:

import { compareDecimal } from 'ordercraft';

compareDecimal('9007199254740993', '9007199254740992'); // 1

Locale sorting is explicit and its Intl.Collator is constructed once:

import { createComparator } from 'ordercraft';

const ro = createComparator({
  strings: 'locale',
  locale: 'ro',
  collator: { sensitivity: 'base', numeric: true },
});

Use locale: 'host' only when host-dependent collation is intentional. Ordinal, code-point, and natural modes do not consult the host locale.

Search, selection, and ranking

import {
  createIndex, createPrefixIndex, lowerBound, selectKth, topK, rank,
} from 'ordercraft';

const index = createIndex(values);
index.find('file2');
index.range(2, 10);

const prefix = createPrefixIndex(values.filter(v => typeof v === 'string'), { select: value => value });
prefix.search('file');

lowerBound([1, 2, 2, 4], 2);    // 1
selectKth([9, 1, 7, 2], 2);      // 7
topK([9, 1, 7, 2], 2);           // [1, 2]
rank([20, 10, 20]);               // [2, 1, 2]

topK supports a bounded heap or selection strategy. selectKth avoids a full sort when only one position matters. Exact and prefix indexes prepare keys once and answer repeated queries with logarithmic bounds.

Unicode fuzzy matching uses code-point Levenshtein distance and supports a distance threshold, NFC normalization, explicit case preparation, and bounded results:

import { createFuzzyIndex } from 'ordercraft';

const search = createFuzzyIndex(['café', 'caffè', 'catalog'], {
  select: value => value,
  normalize: 'NFC',
  case: 'fold',
});

search.search('cafe', { maxDistance: 1, limit: 5 });

Browser and Node

The root import exposes the complete API. Subpaths keep browser bundles small:

| Import | Use | | --- | --- | | ordercraft | Complete API | | ordercraft/compare | Policies and comparator combinators | | ordercraft/sort | Stable sorting and radix sorting | | ordercraft/strings | Ordinal, code-point, and natural string primitives | | ordercraft/decimal | Exact decimal comparison | | ordercraft/search | Bounds and immutable indexes | | ordercraft/selection | selectKth and topK | | ordercraft/rank | Dense, competition, and ordinal ranks | | ordercraft/fuzzy | Distance and fuzzy indexes |

Every public entry supports ESM and CommonJS. The package has no Node-only runtime dependency in its browser-facing code.

Performance

The default sort uses the engine's stable native sort after preparing each key once. An explicit adaptive Powersort path is available for data with useful natural runs, and stable four-pass radix sorting is available for Int32Array and Uint32Array.

On an Apple M4 Pro with Node 24, the optimized natural filename path sorted 10,000 rows in 9.36 ms, compared with 12.28 ms for natural-orderby 5.0.0 in the same run. The result is workload-specific: cached Intl.Collator is faster for homogeneous locale strings, and the full root bundle is larger than a single purpose library. Ordercraft's advantage is a lawful mixed-value contract plus composable search and selection primitives.

See PERFORMANCE.md for the release snapshot. Timing claims include the machine, input shape, warmups, batch count, uncertainty, and bundle cost.

API surface

| Area | Exports | | --- | --- | | Policies | createOrder, createComparator, compare, by, chain, reverse, nullsFirst, nullsLast | | Strings | ordinal, codePoint, natural, prepareNatural, compareNaturalTokens | | Sorting | sort, sortInPlace, orderBy, adaptiveSortInPlace, radixSort | | Search | lowerBound, upperBound, equalRange, binarySearch, createIndex, createPrefixIndex | | Selection | selectKth, topK | | Ranking | rank | | Exact numbers | compareDecimal | | Fuzzy | levenshtein, createFuzzyIndex | | Diagnostics | auditComparator |

Compatibility

The ordering contract is deterministic for supported JavaScript primitives. The default policy sorts numbers before strings and leaves numeric-looking strings as strings. This is a product rule; choose numericStrings: 'coerce' when your data model says otherwise.

Locale order depends on the selected engine's ICU data. Fuzzy distance counts Unicode code points, not grapheme clusters, and does not transliterate or perform substring matching. Bound searches require an array already sorted by the same comparator. auditComparator is an exhaustive finite-pool diagnostic, not a mathematical proof for all possible values.

Contributing

Run the full local checks before opening an issue or proposing a change:

npm ci
npm test
npm run typecheck
npm run bench:check
npm run package:check
npm run browser:check

The release process also validates the exact packed archive and records its integrity before publication. See PERFORMANCE.md for the release benchmark snapshot and CHANGELOG.md for version history.

License

Ordercraft is released under the MIT License. The adaptive merge scheduler includes the notice required for its Python Software Foundation source adaptation; see THIRD_PARTY_NOTICES.