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

@uphold/eslint-plugin-import-direction

v0.2.0

Published

An ESLint plugin that enforces import direction: ancestor imports use a root alias, sibling and descendant imports stay relative.

Readme

@uphold/eslint-plugin-import-direction

An ESLint plugin that enforces import direction:

  • Ancestor imports (anything that would traverse ../) must use a root alias.
  • Sibling and descendant imports (same directory or below) must stay relative (./).

The alias is read straight from your package.json imports field (e.g. "#/*": "./*"), so it works with Node subpath imports — no tsconfig paths or bundler required.

Installation

npm install --save-dev @uphold/eslint-plugin-import-direction

Then declare the alias once in your package.json:

{
  "imports": {
    "#/*": "./*"
  }
}

Usage

Flat config (eslint.config.js) — enable the recommended preset:

import importDirection from '@uphold/eslint-plugin-import-direction';

export default [importDirection.configs.recommended];

Or register the plugin and pick rules explicitly:

import importDirection from '@uphold/eslint-plugin-import-direction';

export default [
  {
    plugins: { '@uphold/import-direction': importDirection },
    rules: {
      '@uphold/import-direction/no-relative-parent': 'error',
      '@uphold/import-direction/no-aliased-local': 'error'
    }
  }
];

Both rules are autofixable, so eslint . --fix migrates an existing codebase in one pass.

Configuration

By default the alias prefix and root directory are auto-detected from the nearest package.json imports field. To override (or for setups without an imports field), pass options to either rule:

'@uphold/import-direction/no-relative-parent': ['error', { aliasPrefix: '#/', rootDir: import.meta.dirname }]

| Option | Type | Description | | --- | --- | --- | | aliasPrefix | string | The import alias prefix, e.g. "#/". | | rootDir | string | Absolute path the alias prefix maps to. | | moduleRoots | string[] | Glob patterns marking module-root directories. See below. |

Module roots

By default the alias is required for any import that traverses ../, even between two files in the same cohesive sub-module. For example, with the file src/repositories/processes/create.ts importing a sibling utility:

// ❌ forced by default
import { getDb } from '#/src/repositories/utils/db-options.ts';

moduleRoots lets you mark directories as module roots (glob patterns matched against the directory path relative to the alias root, in posix form). Imports that stay within the same module root are then treated like local imports — kept relative rather than aliased:

'@uphold/import-direction/no-relative-parent': ['error', { moduleRoots: ['src/repositories'] }]
// ✅ allowed, because both files live under the src/repositories module root
import { getDb } from '../utils/db-options.ts';

The direction philosophy still holds across module boundaries: a ../ import that leaves its module root must use the alias. With no-aliased-local, an alias pointing at a file within the same module root is rewritten to the relative form.

Rules

💼 Configurations enabled in.
✅ Set in the recommended configuration.
🔧 Automatically fixable by the --fix CLI option.

| Name               | Description | 💼 | 🔧 | | :----------------------------------------------------- | :------------------------------------------------------------------------------------------------ | :- | :- | | no-aliased-local | Disallow aliased imports for files within the same directory subtree in favor of relative imports | ✅ | 🔧 | | no-relative-parent | Disallow relative parent imports in favor of the configured root alias | ✅ | 🔧 |

License

MIT