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

locitree

v0.0.1

Published

Locitree is a small TypeScript DSL for describing related locations as an inferred, type-safe tree. It is useful when filesystem paths, object keys, routes, or namespaced identifiers are assembled in many places and should have one discoverable API instea

Readme

Locitree

Locitree is a small TypeScript DSL for describing related locations as an inferred, type-safe tree. It is useful when filesystem paths, object keys, routes, or namespaced identifiers are assembled in many places and should have one discoverable API instead of repeated string concatenation.

Locitree only builds strings. It does not access the filesystem, create directories, or check whether a location exists.

Install

npm install locitree

Filesystem paths

Import defineLocation from locitree/node to join segments with Node.js path.join. This gives paths the separators and normalization rules of the current platform.

Filesystem results below use POSIX separators (/). On Windows, path.join uses platform-native separators.

import { mkdir, readFile } from 'node:fs/promises'
import { defineLocation } from 'locitree/node'

const locations = defineLocation(process.cwd(), (inRoot) => ({
  source: inRoot('src', (inSource) => ({
    entry: inSource('index.ts'),
    features: inSource('features', (inFeatures) => ({
      byName: (name) => inFeatures(name),
    })),
  })),
  output: inRoot('dist'),
}))

await readFile(locations.source.entry.toString(), 'utf8')
await mkdir(locations.output.toString(), { recursive: true })

const billingDirectory = locations.source.features.byName('billing').toString()

The callback receives a factory for locations under the current node. Naming it after that context (inRoot, inSource, and so on) makes every segment relative to the right parent. Static properties are created immediately; functions such as byName create dynamic locations when called.

Builder arguments

A location builder may accept any number of arguments. Unannotated arguments are contextually typed as string; explicit annotations are preserved in the inferred tree API.

import { defineLocation } from 'locitree/node'

const locations = defineLocation('data', (inData) => ({
  reports: inData('reports', (inReports) => ({
    // year and month are both inferred as string
    monthly: (year, month) => inReports(`${year}-${month}.csv`),
  })),
  snapshots: inData('snapshots', (inSnapshots) => ({
    // Explicit types can model the values accepted by this location.
    at: (createdAt: Date, shard: number) =>
      inSnapshots(`${createdAt.toISOString().slice(0, 10)}-${shard}.json`),
  })),
}))

// data/reports/2026-08.csv
locations.reports.monthly('2026', '08').toString()

// data/snapshots/2026-08-14-3.json
locations.snapshots.at(new Date('2026-08-14'), 3).toString()

Both builders above take multiple arguments. TypeScript rejects a number passed as year, or a string passed where at expects a Date or number.

The relative inLocation factory itself accepts a string segment and, optionally, another child-definition callback. Put domain arguments on a named builder, then turn them into a segment with inLocation, as monthly and at do above.

Other location formats

The core withJoin export applies the same tree API to any string hierarchy. For example, telemetry names can use dots instead of filesystem separators:

import { withJoin } from 'locitree'

const defineMetric = withJoin((...parts) => parts.join('.'))

const metrics = defineMetric('checkout', (inCheckout) => ({
  payment: inCheckout('payment', (inPayment) => ({
    failed: inPayment('failed'),
  })),
}))

metrics.payment.failed.toString() // checkout.payment.failed

The same approach works for URL paths, object-storage keys, cache keys, and other values whose segments have a consistent joining rule.

Segment safety

Locitree does not validate or escape segments. Validate untrusted input before passing it to a builder: .. can escape a filesystem root, separators may change the hierarchy, and URL segments are not encoded automatically.

API

defineLocation(rootPath, defineChildren?)

Available from locitree/node. Creates a root filesystem location and joins nested segments with node:path.join. The returned root is also a location node, so its toString() returns rootPath.

withJoin(join)

Available from locitree. Creates a location factory using the supplied string joining function. The returned factory has the same signature as defineLocation.

Location nodes

Every location node:

  • exposes the child nodes and builders returned by its definition callback;
  • returns its fully resolved string from toString();
  • is shallowly frozen, so its own properties cannot be added, removed, or reassigned.

The definition callback runs when its node is created. toString is reserved for the node method.

Locitree performs no I/O. Pass node.toString() to filesystem, network, or SDK APIs that consume the resolved location.

Compatibility

  • Node.js ^14.18.0 or >=16.0.0.
  • ESM and CommonJS builds are included.
  • locitree uses no Node.js APIs; locitree/node uses node:path and is Node.js-only.
  • TypeScript is optional. JavaScript has the same runtime API without inferred type safety.

Project