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

eslint-config-mrhen

v1.0.3

Published

An extremely opinionated ESLint config

Downloads

12

Readme

eslint-config-mrhen

An extremely opinionated ESLint config

Motivation

There are already a handful of high-quality existing configurations. Notably: eslint-config-airbnb, eslint-config-xo and eslint-config-standard. Why make another config?

Protect meaningful visual shape

Reading and scanning code quickly requires a meaningful visual shape. This is especially true if you are in a position where you need to context switch between multiple languages throughout a single day or week of work.

In paritcular, complexity is one of the most important things to detect quickly. Many of the rules in this config attempt to align visual shape in a way that makes it easier to quickly estimate complexity. This helps maintainers and code reviewers hunt down problematic areas in code.

Examples

[1,2,3].map((i) => { return i; }); // A

[1,2,3].map((i) => { // B
    return i;
});

A return statement being on its own line makes it easier to detect that a function exists by forcing indentation to appear in the visual flow. While keyword highlighting can make the return statement pop, the extra line with its indentation means you only need to look at the whitespace to quickly notice the complexity hidden by the callback.


// A
function render() {
    const showContent = true;

    return (
        <Outer>
            {showContent && <Content />}
        </Outer>
    );
}

// B
function render() {
    const showContent = true;

    return (
        <Outer>
            {showContent && (
                <Content />
            )}
        </Outer>
    );
}

Two things are accomplished by moving <Content /> to its own line. First, the branching logic of showContent is now highlighted by the whitespace indentation. Second, having JSX opening tags on their own line makes for easy scanning of the layout hierarchy.


// A
function doFoo() {
    const a = 'a';
    const b = 'b';
    const c = 'c';



    const d = 'd';
    const e = 'e';


    const f = 'f';
}

// B
function doFoo() {
    const a = 'a';
    const b = 'b';
    const c = 'c';

    const d = 'd';
    const e = 'e';

    const f = 'f';
}

Extraneous blank lines hurt readability by incorrectly signaling an important syntactical element. JavaScript uses curly braces to denote scope blocks and, therefore, more than one blank line is rarely needed. Python does not, however, so multiple blank lines are used to signal differences between areas in code.

Rapidly switching between JavaScript and Python is hard enough already. Unnecessary and meaningless blank lines make it harder.

Consistency over conciseness

There are a lot of different ways to write the same functional code. Most styles let the author choose the pattern appropriate for the circumstance -- but many coders prefer consise code over consistent style. This config deliberately limits style to the most readable variant that also covers the majority of situations. It pushes back against the temptation to reduce line count for the sake of brevity -- it is often more readable to leave it in a more verbose form.

Examples

[1,2,3].map(i => i);   // A

[1,2,3].map((i) => i); // B

[1,2,3].map((i) => { return i; }); // C

[1,2,3].map((i) => {   // D
    return i;
});

Option (D) is three times longer than (A) but it only works in a particular scenario. It is better to have the same visual shape for code that behaves the same:

[1,2,3].map((i) => {   // D.1
    return i;
});

[1,2,3].map((i) => {   // D.2
    const foo = i;
    return foo * foo;
});

const { foo } = this; // A.1

const {
    foo,
} = this; // B.1

Option (B) is three times longer but at some point (A) crams too many declarations into one line:

const { alfa, beta, charlie, delta, echo, foxtrot, golf, hotel } = this; // A.2

const {
    alfa,
    beta,
    charlie,
    delta,
    echo,
    foxtrot,
    golf,
    hotel,
} = this; // B.2

Since (B.2) is preferable over (A.2), (B.1) is preferable over (A.1).

Avoid surprises

Don't be clever. Code that requires lots of comments or documentation tends to be overly complicated. Code that is dense or uses too much syntactic sugar is hard to read and can lead to results that surprise the reader.

Examples

// A
const foo = alfa ? 1 : beta ? charlie ? 1000 : 100 : 0;

// B
let foo;
if (alfa) {
    foo = 1;
} else if (beta) {
    if (charlie) {
        foo = 1000
    } else {
        foo = 100;
    }
} else {
    foo = 0;
}

Ternaries are notoriously difficult to read and nested ternaries are all-around terrible.


function doFoo(numbers) {
    for (const number in numbers) {
        switch(number) {
            case 0:
                console.log('Zero');
                break;
            case 1:
                console.log('One');
                break;
            case 2:
                console.log('Two');
                break;
            case 3:
                console.log('Three');
                return;
            case 4:
                console.log('Four');
                break;
            case 5:
                console.log('Five');
                break;
            default:
                console.log('More than Five');
        }
    }
}

Code branches should act like other nearby code branches. If a branch has special logic or behavior it should be immediately obvious. (Sadly, there is no rule currently checking for the above scenario.)

Optimize for common scenarios

ESLint provides easy ways to mark lines of code as exceptions. Not every lint error will be completely accurate -- that does not mean the rule should be unused. That means the rule should be used and the exceptions marked with an explanation.

Prioritize clean code reviews

Code reviews and code diffs happen frequently and diff noise makes it harder to see what changes were being made.

// A
const {
    alfa,
    beta,
-   charlie
+   charlie,
+   delta
} = this;

// B
const {
    alfa,
    beta,
    charlie,
+   delta,
} = this;

Only one change was made but (a) flags an extra line as having changed because of a meaningless comma.