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
| Aspect | Details |
|---|---|
| Severity | Warning (code quality) |
| Auto-Fix | ❌ No (requires refactoring) |
| Category | Quality |
| ESLint MCP | ✅ Optimized for ESLint MCP integration |
| Best For | Code 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
maxStatementsstatements, or - nests control flow (
if, loops,switch,try) more thanmaxDepthlevels 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
| Option | Type | Default | Description |
|---|---|---|---|
maxStatements | number | 3 | Most statements the IIFE body may hold |
maxDepth | number | 2 | Deepest control-flow nesting allowed inside the IIFE |
allowReturningIIFE | boolean | true | An 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 }],
},
},
];Related Rules
cognitive-complexity- Code complexity limits
Further Reading
- IIFE - MDN - IIFE pattern explanation
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{ "jsPlugins": ["oxlint-plugin-maintainability"], "rules": { "maintainability/no-unreadable-iife": "error" }}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.