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-plugin-guard-clauses

v0.0.1

Published

ESLint plugin to enforce guard clauses and reduce code nesting

Readme

eslint-plugin-guard-clauses

ESLint plugin to enforce guard clauses and reduce code nesting for cleaner, more readable code.

Installation

pnpm add -D eslint-plugin-guard-clauses

Usage

ESLint 9+ (Flat Config)

import guardClauses from 'eslint-plugin-guard-clauses';

export default [
  {
    plugins: {
      'guard-clauses': guardClauses
    },
    rules: {
      'guard-clauses/if-else-to-early-return': 'warn'
    }
  }
];

Or use the recommended config:

import guardClauses from 'eslint-plugin-guard-clauses';

export default [
  {
    plugins: {
      'guard-clauses': guardClauses
    }
  },
  guardClauses.configs.recommended
];

Or use the strict config (all rules as errors):

import guardClauses from 'eslint-plugin-guard-clauses';

export default [
  {
    plugins: {
      'guard-clauses': guardClauses
    }
  },
  guardClauses.configs.strict
];

Configs

  • recommended: All rules enabled as warnings
  • strict: All rules enabled as errors

Rules

if-else-to-early-return

Suggests using early return instead of if-else when both branches return a value.

Problem

Functions that consist only of an if-else statement where both branches return can be simplified using early return pattern (guard clauses).

// Bad
function checkAge(age) {
  if (age >= 18) {
    return 'adult';
  } else {
    return 'minor';
  }
}

Solution

Invert the condition and return early, then return the default case:

// Good
function checkAge(age) {
  if (age < 18) {
    return 'minor';
  }
  return 'adult';
}

Benefits

  • Reduces nesting and cognitive complexity
  • Makes the code flow more linear and easier to read
  • Eliminates unnecessary else blocks
  • Follows the guard clause pattern

When it triggers

This rule will flag a function when ALL of these conditions are met:

  1. The function body contains ONLY an if-else statement (no other statements)
  2. Both the if and else branches end with a return statement
  3. Works with function declarations, function expressions, and arrow functions

When it won't trigger

  • Functions with multiple statements
  • If statements without an else clause
  • When only one branch returns
  • Arrow functions with expression bodies (e.g., x => x ? a : b)
  • When there are statements before or after the if-else

no-else-return

Disallow else blocks after return statements in if blocks.

// Bad
function foo(x) {
  if (x) {
    return true;
  } else {
    doSomething();
  }
}

// Good
function foo(x) {
  if (x) {
    return true;
  }
  doSomething();
}

Rationale: If the if block contains a return statement, the else block is unnecessary because the code will only reach that point if the condition was false.


prefer-guard-clauses

Prefer guard clauses to reduce nesting depth.

// Bad
function processUser(user) {
  if (user) {
    if (user.isActive) {
      if (user.hasPermission) {
        return doWork(user);
      }
    }
  }
  return null;
}

// Good
function processUser(user) {
  if (!user) return null;
  if (!user.isActive) return null;
  if (!user.hasPermission) return null;
  return doWork(user);
}

Benefits: Guard clauses reduce cognitive complexity by flattening nested if statements. The main logic becomes more prominent and easier to follow.


if-else-chain-to-early-return

Convert if/else-if/else chains to early returns for better readability.

// Bad
function getStatus(code) {
  if (code === 200) {
    return 'OK';
  } else if (code === 404) {
    return 'Not Found';
  } else if (code === 500) {
    return 'Error';
  } else {
    return 'Unknown';
  }
}

// Good
function getStatus(code) {
  if (code === 200) return 'OK';
  if (code === 404) return 'Not Found';
  if (code === 500) return 'Error';
  return 'Unknown';
}

Note: This rule only triggers for chains with 2 or more else-if clauses to avoid false positives on simple if-else statements.


no-nested-ternary-return

Discourage nested ternary expressions in return statements.

// Bad
function getLevel(score) {
  return score > 90 ? 'A' : score > 80 ? 'B' : score > 70 ? 'C' : 'F';
}

// Good
function getLevel(score) {
  if (score > 90) return 'A';
  if (score > 80) return 'B';
  if (score > 70) return 'C';
  return 'F';
}

Rationale: Nested ternaries are hard to read and maintain. Using if statements with early returns makes the logic clearer.


reduce-boolean-return

Simplify boolean returns from if-else statements by returning the condition directly.

// Bad
function isValid(x) {
  if (x > 10) {
    return true;
  } else {
    return false;
  }
}

// Good
function isValid(x) {
  return x > 10;
}

Rationale: When an if-else statement only returns boolean literals, you can return the condition (or its negation) directly.


no-else-if-after-return

Disallow else if blocks after return statements in if blocks.

// Bad
function classify(x) {
  if (x > 10) {
    return 'high';
  } else if (x > 5) {
    return 'medium';
  } else {
    return 'low';
  }
}

// Good
function classify(x) {
  if (x > 10) return 'high';
  if (x > 5) return 'medium';
  return 'low';
}

Rationale: When an if block returns, else if is redundant since the code won't continue. Using independent if statements reduces nesting and makes the code more linear.


prefer-early-continue

Prefer early continue in loops to reduce nesting.

// Bad
for (const item of items) {
  if (item.isValid) {
    processItem(item);
    doMore();
  }
}

// Good
for (const item of items) {
  if (!item.isValid) continue;
  processItem(item);
  doMore();
}

Benefits: Early continue statements reduce nesting in loops, making the main logic easier to follow. This is the loop equivalent of early return.


no-lonely-if

Disallow if statements as the only statement in else blocks.

// Bad
if (x > 10) {
  console.log('high');
} else {
  if (x > 5) {
    console.log('medium');
  }
}

// Good
if (x > 10) {
  console.log('high');
} else if (x > 5) {
  console.log('medium');
}

Rationale: A lonely if in an else block adds unnecessary nesting. Using else if is clearer and more idiomatic.


prefer-guard-at-function-start

Prefer guard clauses at the start of functions.

// Bad
function processUser(user) {
  doSetup();
  if (!user) return null; // Guard should be first
  return user.data;
}

// Good
function processUser(user) {
  if (!user) return null; // Guard at top
  doSetup();
  return user.data;
}

Benefits: Guard clauses at the start validate inputs early, following the "fail fast" principle. This prevents unnecessary work and makes preconditions explicit.

Development

Setup

pnpm install

Testing

pnpm test         # Run tests once
pnpm test:watch   # Run tests in watch mode

Linting

pnpm lint         # Check for linting errors
pnpm lint:fix     # Fix linting errors

Release

pnpm release

License

ISC