Skip to main content
interlace
Plugin: maintainabilityRules

no-unreadable-iife

Disallow unreadable IIFE (Immediately Invoked Function Expression) patterns

Disallow unreadable IIFE (Immediately Invoked Function Expression) patterns. This rule is part of eslint-plugin-maintainability.

Quick Summary

AspectDetails
SeverityWarning (code quality)
Auto-Fix❌ No (requires refactoring)
CategoryQuality
ESLint MCP✅ Optimized for ESLint MCP integration
Best ForCode readability, avoiding confusing patterns

Rule Details

An immediately invoked function expression (IIFE) is a function or arrow expression called on the spot: (() => { ... })(), (function () { ... })(), async too, and through .call(...) / .apply(...). A long one hides logic a named function would document. The rule reports an IIFE whose block body:

  • holds more than maxStatements statements, or
  • nests control flow (if, loops, switch, try) more than maxDepth levels deep.

A short IIFE is not reported for holding a single if or try, declaring a helper, or taking several parameters: none of those exceeds a limit. The (async () => { try { await main(); } catch (e) { ... } })() entry point is the standard pattern.

Configuration

OptionTypeDefaultDescription
maxStatementsnumber3Most statements the IIFE body may hold
maxDepthnumber2Deepest control-flow nesting allowed inside the IIFE
allowReturningIIFEbooleantrueAn IIFE that returns a value is a scoped initializer: its statement count is not checked (its nesting still is)

Examples

❌ Incorrect

(() => {
  const a = read();
  const b = read();
  use(a);
  use(b);
})();

(function () {
  if (ready()) {
    for (const x of list()) {
      if (x) use(x); // depth 3
    }
  }
}).call(this);

✅ Correct

// Named function for clarity
function processValue() {
  return value;
}
const result = processValue();

// A scoped initializer (allowReturningIIFE)
const config = (() => {
  const env = process.env.NODE_ENV;
  const debug = env === 'development';
  const level = debug ? 'debug' : 'info';
  return { env, debug, level };
})();

// The async entry point
(async () => {
  try {
    await main();
  } catch (error) {
    fail(error);
  }
})();

Configuration Examples

// eslint.config.mjs
export default [
  {
    rules: {
      'maintainability/no-unreadable-iife': ['warn', { maxStatements: 5 }],
    },
  },
];

Further Reading

Known False Negatives

Expression-bodied IIFEs

Why: an arrow with an expression body is one expression, however long.

// ❌ NOT DETECTED
const v = ((a) => a && a.b && a.b.c && a.b.c.d)(input);

Use this rule

npm install -D oxlint-plugin-maintainability
.oxlintrc.json
{  "jsPlugins": ["oxlint-plugin-maintainability"],  "rules": {    "maintainability/no-unreadable-iife": "error"  }}
vite.config.ts
import { defineConfig } from 'vite-plus';export default defineConfig({  lint: {    jsPlugins: ['oxlint-plugin-maintainability'],    rules: {      'maintainability/no-unreadable-iife': 'error',    },  },});

oxlint-plugin-maintainability re-exports eslint-plugin-maintainability/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.

Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.