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

path-search-sort

v1.2.0

Published

Search, filter, and sort file paths, ranked the way a human expects

Readme

path-search-sort

Search, filter, and sort file paths, ranked the way a human expects.

npm version jsDelivr License: MPL 2.0

Features

  • Exact names first, then starts-with, then contains, in natural order
  • Directory and RegExp queries: block/stone, /shot_\d+/
  • Scope by root, folders, extensions, or your own filter
  • Forgiving: case, pasted paths, and either slash direction all just work

Install

For Node.js, or the browser through a bundler:

npm install path-search-sort

Or in the browser, import it straight from a CDN:

import pathSearch from "https://cdn.jsdelivr.net/npm/path-search-sort/+esm"

Examples

import pathSearch from "path-search-sort"

const paths = [
  "img/photo.png",
  "img/old/photo.png",
  "img/photo_edit.jpg",
  "screenshots/2024/shot_2.png",
  "screenshots/2024/shot_10.png",
  "screenshots/2025/my_shot.png",
  "backup/2024/screenshot.jpg",
  "backup/Shot.png"
]

pathSearch(paths, "photo")       // every file with photo in its name, best matches first
pathSearch(paths, "img/photo")   // files starting with photo under an img/ folder only
pathSearch(paths, /shot_\d+/)    // a RegExp works too, ranked by where it hits

// where to look
pathSearch(paths, "shot", { root: "screenshots" })  // only from the top of the tree
pathSearch(paths, "shot", { path: "2024" })         // only through a 2024/ folder, wherever it sits

// what to keep
pathSearch(paths, "shot", { extension: ["png", "jpg"] })         // only those extensions
pathSearch(paths, "shot", { filter: p => !p.endsWith(".jpg") })  // your own custom filter
pathSearch(paths, "shot", { limit: 25 })                         // top 25 after sorting

// how to match
pathSearch(paths, "screenshot", { folders: false })  // the file, not the screenshots/ folder
pathSearch(paths, "Shot", { caseSensitive: true })   // case matters
pathSearch(paths, "my shot", { spaces: "_" })        // typed spaces mean underscores

// items can be strings or objects with a .path, with either slash direction;
[
  "img\\photo.png",
  { path: "img/old/photo.png" }
]
// whatever went in comes back untouched

Options

pathSearch(items, query, options), and all options are optional:

| Option | Default | Description | |---|---|---| | root | (everywhere) | Only paths starting with this prefix | | path | (everywhere) | Only paths passing through these folders, wherever they sit | | extension | (all) | Only these file types: one extension or several, leading dot optional | | filter | (none) | Your own predicate over the item, only called for what already matched | | limit | (all) | Cap on results, applied after sorting | | folders | true | Also match folder names: files inside a matching folder rank after name matches | | caseSensitive | false | Case matters, except for the extension filter; RegExp queries ignore it | | spaces | (kept) | What a typed space becomes, e.g. "_" for underscore-named files; RegExp queries ignore it |

How it matches

Matching is on the full filename, extension included, and case insensitive. A directory in the query constrains it: block/stone means a stone under a block/ folder wherever that sits. Folder names are matched too, so a file inside a matching folder is found even when its own name does not match, and block/ on its own lists everything under block folders. folders: false narrows all of that to file names alone, where a bare block/ then matches nothing.

RegExp queries are also supported and run globally over the path: every hit is found and the best-placed one does the ranking. The casing is case sensitive in RegEx mode: the caseSensitive and spaces options are ignored.

How it sorts

const results = pathSearch(paths, "stone")

// results
[
  "stone.png",                          // exact name first, the extension not counting
  "ore/stone.png",                      // equal names: the shallower path wins
  "stone_axe.png",                      // then names starting with the query
  "stone_axe_2.png",                    // in natural order within every tier
  "stone_axe_10.png",                   // so 10 after 2
  "stonework.png",                      // but whole words go first, so this one waits
  "smooth_stone.png",                   // then names containing the query
  "redstone.png",                       // buried in a word, so last of those too
  "stone/gravel.png",                   // folder matches last: an exact stone folder
  "mine/stone/ores/coal.png",           // the earlier the matching segment the better
  "mine/stone/deep/dark/caves/gem.png", // no matter how deep the path goes on
  "mine/ores/stone/iron.png",           // a later stone comes after
  "stonework/gravel.png",               // then a folder starting with stone
  "old_stone/gravel.png"                // then a folder containing it
]

Also exported

import { naturalCompare } from "path-search-sort"

names.sort(naturalCompare)

naturalCompare is the comparator on its own, for sorting anything.

License

MPL-2.0 © Ewan Howell