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

@bravobit/eslint-plugin-waterfall

v2.0.2

Published

ESLint plugin that sorts imports and CSS/SCSS declarations by line length, longest first — the waterfall.

Readme

@bravobit/eslint-plugin-waterfall

ESLint plugin that sorts by line length, longest first — the visual "waterfall". It does this in two places:

  • waterfall/sort-imports — top-level imports in JS/TS files;
  • waterfall/sort-declarations — declarations inside the braces of CSS and SCSS rules (there the waterfall runs the other way: shortest first), via the built-in waterfall/css language.

No grouping by origin, no alphabetizing, no options to study. Just the ladder.

// imports, after --fix
import {ChangeDetectionStrategy, Component, ElementRef, inject, OnInit} from '@angular/core';
import {BbAvatar, BbButton, BbFormControl, BbIcon} from '@bravobit/bb-foundation/elements';
import {toSignal} from '@angular/core/rxjs-interop';
import {RouterLink} from '@angular/router';
// scss, after --fix — shortest first
.button {
    color: white;
    display: flex;
    border-radius: 4px;
    background-color: $color-primary;

    &:hover {
        cursor: pointer;
        background-color: $color-primary-dark;
    }
}

The sort key for imports: length of the statement as one line (UTF-16 code units), then — on a tie — the position of the from keyword (furthest right first), then the original order (stable). Declarations sort the other way around — shortest first, with the position of the : (furthest left first) as tiebreaker — so a block widens toward its base. Multiline statements are measured as one line but never reformatted.

Comments travel with their statement; license headers and directive comments (eslint-disable, stylelint-disable, @ts-*, prettier-ignore, …) stay exactly where they are and act as sort boundaries. Blank lines split statements into independently sorted groups.

Install

npm install -D @bravobit/eslint-plugin-waterfall

Requires ESLint ^9.15.0 || ^10.0.0 (flat config) and Node 20.19+, 22.13+ or 24+.

Usage

// eslint.config.js / eslint.config.mjs
import waterfall from '@bravobit/eslint-plugin-waterfall';

export default [
  ...waterfall.configs.recommended, // both rules as "warn", js/ts + css/scss
];

CommonJS works identically (const waterfall = require('@bravobit/eslint-plugin-waterfall')).

Or configure by hand:

export default [
  {
    files: ['**/*.{js,ts}'],
    plugins: { waterfall },
    rules: { 'waterfall/sort-imports': 'warn' },
  },
  {
    files: ['**/*.{css,scss}'],
    plugins: { waterfall },
    language: 'waterfall/css',
    rules: { 'waterfall/sort-declarations': 'warn' },
  },
];

Rules

| Rule | Description | | --- | --- | | waterfall/sort-imports | Sort top-level imports by line length, longest first. | | waterfall/sort-declarations | Sort CSS/SCSS declarations by line length, shortest first. |

Options

Deliberately minimal:

| Rule | Option | Default | Behaviour | | --- | --- | --- | --- | | sort-imports | pinSideEffectImports | true | import 'polyfill' keeps its position; the rest sorts around it. Turning this off can change runtime behaviour. | | both | pinnedCommentPattern | – | Extra regex for comments that must never move, on top of the built-in directive list. |

Everything else is fixed behaviour: imports longest first, declarations shortest first, blank lines split groups, comments move with their statement, groups need at least two entries.

What sort-declarations will not touch

  • SCSS variables ($x: …) — order-dependent, they stay put and split groups.
  • At-rules (@include, @extend, …) and nested rules — boundaries.
  • Duplicate properties in one group (display: -webkit-box; display: flex;) — cascade fallbacks whose order is meaning, the whole group is left alone.
  • Anything the tolerant scanner does not recognise — unknown syntax becomes a boundary, never a rewrite.

Does this work with Prettier / stylelint?

At a normal printWidth, Prettier wraps long imports onto multiple lines and the visual waterfall disappears (the rule still measures wrapped statements correctly). Set printWidth high enough that imports stay on one line, or accept the effect only where they do. Stylelint's ordering rules (order/properties-alphabetical-order etc.) fight sort-declarations — enable one, not both.

Sorting inside the import braces

waterfall/sort-imports orders whole lines, not the names inside { … }. For alphabetical specifiers use ESLint core, which composes cleanly:

rules: {
  'waterfall/sort-imports': 'warn',
  'sort-imports': ['warn', { ignoreDeclarationSort: true, ignoreCase: true }],
}

Why not eslint-plugin-perfectionist?

Perfectionist can sort by line length, but its fallbackSort cannot break ties on the position of the from keyword — exactly the lines where the waterfall is most visible. If you run both, disable perfectionist/sort-imports and import/order.

Adopting in an existing codebase

The first --fix touches a lot of lines. Do it as a separate, mechanical commit so reviews and git blame stay usable.

Non-goals

No grouping by category, no alphabetical sorting of statements, no blank-line management, no reformatting (multiline ↔ single line), no deduplication, no export … from sorting, no LESS/Stylus.

License

MIT © Bravobit