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

@theholocron/fs-utils

v1.16.0

Published

Walk a directory tree upward to find the nearest match or project root.

Readme

@theholocron/fs-utils

Walk a directory tree upward to find the nearest match or project root.

Installation

pnpm add @theholocron/fs-utils

Usage

import {
  findExecutable,
  findExecutableSync,
  findRoot,
  findUpward,
  hasGitEntry,
  isWorkspaceRoot,
  walkFilesSync,
} from "@theholocron/fs-utils";

// nearest ancestor holding a marker file or directory
const repoRoot = await findRoot(process.cwd(), ".git");
const monorepoRoot = await findRoot(process.cwd(), ["pnpm-workspace.yaml", "turbo.json"]);

// find the nearest ancestor holding a config file, stopping at the repo root
const configDir = await findUpward(
  process.cwd(),
  async (dir) => ((await fileExists(join(dir, "app.config.json"))) ? dir : undefined),
  hasGitEntry
);

// a plain boundary check, usable as `findUpward`'s `stop` or on its own
await hasGitEntry("/path/to/dir"); // true if a .git entry (file or folder) exists there

// decide whether a pnpm command needs -w at this directory
await isWorkspaceRoot(repoRoot ?? process.cwd());

findUpward(startDir, check, stop?)

Walks upward from startDir — itself first, then its parent, and so on — calling check(dir) at each directory and returning the first result that isn't undefined. When given, stop(dir) is checked only after check has already come back empty for that directory (so it's still fully checked before stopping) — returning true ends the walk there with no result, instead of continuing to the parent. Without stop, walks all the way to the filesystem root. Always terminates: directory nesting is finite.

findRoot(startDir, marker, options?) / findRootSync(...)

The nearest ancestor of startDir — itself first — that contains marker: a file or directory name, or a list of names where any one counts. Resolves to undefined when nothing is found. findRootSync is the synchronous twin. Each marker must be a bare name — an empty string, ., .. or anything with a path separator throws a TypeError, as does any filesystem error other than "not there" (e.g. EACCES). A relative startDir is resolved against the working directory up front, so results are always absolute.

  • options.fallback: "start" — return the start directory instead of undefined when nothing is found (a soft-skip for callers that treat the start dir as the root anyway; always absolute).
  • options.realpath: true — resolve symlinks of startDir before walking, so a symlinked start walks the physical tree instead of the link's own ancestors. A start path that doesn't exist counts as not found.
// a git root that never throws and never returns undefined
const root = findRootSync(cwd, ".git", { fallback: "start", realpath: true });

findExecutable(bin, options?) / findExecutableSync(...)

The first runnable file named bin on options.path (default process.env.PATH), or undefined — a which. Directories and files without the exec bit don't count. bin must be a bare command name (an empty string, ., .. or anything with a path separator throws a TypeError), as does any filesystem error other than "not there" / "not permitted".

  • options.path — directories to search, delimited like PATH on the target platform (: on POSIX, ; on Windows). Empty entries are skipped; relative ones are resolved against the working directory when the call starts, so results are always absolute.
  • options.pathExt / options.platform — on Windows there is no exec bit: bin is tried with each PATHEXT extension (default .COM;.EXE;.BAT;.CMD) unless it already ends in one. An extension containing a path separator throws a TypeError.
// a project-local binary first, then the real PATH
const tsc = findExecutableSync("tsc", { path: join(cwd, "node_modules", ".bin") }) ?? findExecutableSync("tsc");

walkFilesSync(dir, options?)

Every regular file under dir, as absolute paths in a stable (name-sorted, depth-first) order. options.skip names the directories not entered, at any depth (default .git and node_modules; it replaces the default); a file with that name is still listed. Symlinks found while walking are neither followed nor listed, so a link back up the tree can't loop; dir itself is followed if it is a symlink. A subdirectory that can't be read is skipped; dir itself must be readable — its error propagates. The tree is assumed not to change mid-walk.

const sources = walkFilesSync(repoRoot, { skip: [".git", "node_modules", "dist"] });

hasGitEntry(dir)

Returns true when dir has a .git entry — a directory in a normal checkout, a file in a worktree/submodule (existence is all that matters). A common stop boundary for findUpward: treat the nearest .git as the project root, searched but not walked past.

isWorkspaceRoot(dir)

Returns true when dir has a pnpm-workspace.yaml — the file that marks a pnpm workspace root. Several pnpm CLI commands (pnpm add among them) behave differently at a workspace root than in a plain package, so a caller shelling out to pnpm can check this before deciding which flags to pass.

Documentation

Check out The Holocron Archive for more information.