Skip to content

Commit ce8a4b7

Browse files
authored
Add no-unreadable-iife rule (#1765)
1 parent ea6f300 commit ce8a4b7

File tree

7 files changed

+273
-0
lines changed

7 files changed

+273
-0
lines changed

configs/recommended.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ module.exports = {
5252
'unicorn/no-thenable': 'error',
5353
'unicorn/no-this-assignment': 'error',
5454
'unicorn/no-unreadable-array-destructuring': 'error',
55+
'unicorn/no-unreadable-iife': 'error',
5556
'unicorn/no-unsafe-regex': 'off',
5657
'unicorn/no-unused-properties': 'off',
5758
'unicorn/no-useless-fallback-in-spread': 'error',

docs/rules/no-unreadable-iife.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Disallow unreadable IIFEs
2+
3+
<!-- Do not manually modify RULE_NOTICE part. Run: `npm run generate-rule-notices` -->
4+
<!-- RULE_NOTICE -->
5+
*This rule is part of the [recommended](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config) config.*
6+
<!-- /RULE_NOTICE -->
7+
8+
[IIFE](https://en.wikipedia.org/wiki/Immediately_invoked_function_expression) with parenthesized arrow function body is considered unreadable.
9+
10+
## Fail
11+
12+
```js
13+
const foo = (bar => (bar ? bar.baz : baz))(getBar());
14+
```
15+
16+
```js
17+
const foo = ((bar, baz) => ({bar, baz}))(bar, baz);
18+
```
19+
20+
## Pass
21+
22+
```js
23+
const bar = getBar();
24+
const foo = bar ? bar.baz : baz;
25+
```
26+
27+
```js
28+
const getBaz = bar => (bar ? bar.baz : baz);
29+
const foo = getBaz(getBar());
30+
```
31+
32+
```js
33+
const foo = (bar => {
34+
return bar ? bar.baz : baz;
35+
})(getBar());
36+
```

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ Each rule has emojis denoting:
9393
| [no-thenable](docs/rules/no-thenable.md) | Disallow `then` property. || | |
9494
| [no-this-assignment](docs/rules/no-this-assignment.md) | Disallow assigning `this` to a variable. || | |
9595
| [no-unreadable-array-destructuring](docs/rules/no-unreadable-array-destructuring.md) | Disallow unreadable array destructuring. || 🔧 | |
96+
| [no-unreadable-iife](docs/rules/no-unreadable-iife.md) | Disallow unreadable IIFEs. || | |
9697
| [no-unsafe-regex](docs/rules/no-unsafe-regex.md) | Disallow unsafe regular expressions. | | | |
9798
| [no-unused-properties](docs/rules/no-unused-properties.md) | Disallow unused object properties. | | | |
9899
| [no-useless-fallback-in-spread](docs/rules/no-useless-fallback-in-spread.md) | Disallow useless fallback when spreading in object literals. || 🔧 | |

rules/no-unreadable-iife.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict';
2+
const {
3+
isParenthesized,
4+
getParenthesizedRange,
5+
} = require('./utils/parentheses.js');
6+
const toLocation = require('./utils/to-location.js');
7+
8+
const MESSAGE_ID_ERROR = 'no-unreadable-iife';
9+
const messages = {
10+
[MESSAGE_ID_ERROR]: 'IIFE with parenthesized arrow function body is considered unreadable.',
11+
};
12+
13+
const selector = [
14+
'CallExpression',
15+
' > ',
16+
'ArrowFunctionExpression.callee',
17+
' > ',
18+
':not(BlockStatement).body',
19+
].join('');
20+
21+
/** @param {import('eslint').Rule.RuleContext} context */
22+
const create = context => ({
23+
[selector](node) {
24+
const sourceCode = context.getSourceCode();
25+
if (!isParenthesized(node, sourceCode)) {
26+
return;
27+
}
28+
29+
return {
30+
node,
31+
loc: toLocation(getParenthesizedRange(node, sourceCode), sourceCode),
32+
messageId: MESSAGE_ID_ERROR,
33+
};
34+
},
35+
});
36+
37+
/** @type {import('eslint').Rule.RuleModule} */
38+
module.exports = {
39+
create,
40+
meta: {
41+
type: 'suggestion',
42+
docs: {
43+
description: 'Disallow unreadable IIFEs.',
44+
},
45+
hasSuggestions: false,
46+
messages,
47+
},
48+
};

test/no-unreadable-iife.mjs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import outdent from 'outdent';
2+
import {getTester} from './utils/test.mjs';
3+
4+
const {test} = getTester(import.meta);
5+
6+
test.snapshot({
7+
valid: [
8+
'const foo = (bar => bar)();',
9+
outdent`
10+
const foo = (() => {
11+
return a ? b : c
12+
})();
13+
`,
14+
],
15+
invalid: [
16+
'const foo = (() => (a ? b : c))();',
17+
outdent`
18+
const foo = (() => (
19+
a ? b : c
20+
))();
21+
`,
22+
outdent`
23+
const foo = (
24+
() => (
25+
a ? b : c
26+
)
27+
)();
28+
`,
29+
outdent`
30+
const foo = (() => (
31+
a, b
32+
))();
33+
`,
34+
outdent`
35+
const foo = (() => ({
36+
a: b,
37+
}))();
38+
`,
39+
'const foo = (bar => (bar))();',
40+
outdent`
41+
(async () => ({
42+
bar,
43+
}))();
44+
`,
45+
outdent`
46+
const foo = (async (bar) => ({
47+
bar: await baz(),
48+
}))();
49+
`,
50+
'(async () => (( {bar} )))();',
51+
],
52+
});
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# Snapshot report for `test/no-unreadable-iife.mjs`
2+
3+
The actual snapshot is saved in `no-unreadable-iife.mjs.snap`.
4+
5+
Generated by [AVA](https://avajs.dev).
6+
7+
## Invalid #1
8+
1 | const foo = (() => (a ? b : c))();
9+
10+
> Error 1/1
11+
12+
`␊
13+
> 1 | const foo = (() => (a ? b : c))();␊
14+
| ^^^^^^^^^^^ IIFE with parenthesized arrow function body is considered unreadable.␊
15+
`
16+
17+
## Invalid #2
18+
1 | const foo = (() => (
19+
2 | a ? b : c
20+
3 | ))();
21+
22+
> Error 1/1
23+
24+
`␊
25+
> 1 | const foo = (() => (␊
26+
| ^␊
27+
> 2 | a ? b : c␊
28+
| ^^^^^^^^^^␊
29+
> 3 | ))();␊
30+
| ^^ IIFE with parenthesized arrow function body is considered unreadable.␊
31+
`
32+
33+
## Invalid #3
34+
1 | const foo = (
35+
2 | () => (
36+
3 | a ? b : c
37+
4 | )
38+
5 | )();
39+
40+
> Error 1/1
41+
42+
`␊
43+
1 | const foo = (␊
44+
> 2 | () => (␊
45+
| ^␊
46+
> 3 | a ? b : c␊
47+
| ^^^^^^^^^^^␊
48+
> 4 | )␊
49+
| ^^^ IIFE with parenthesized arrow function body is considered unreadable.␊
50+
5 | )();␊
51+
`
52+
53+
## Invalid #4
54+
1 | const foo = (() => (
55+
2 | a, b
56+
3 | ))();
57+
58+
> Error 1/1
59+
60+
`␊
61+
> 1 | const foo = (() => (␊
62+
| ^␊
63+
> 2 | a, b␊
64+
| ^^^^^␊
65+
> 3 | ))();␊
66+
| ^^ IIFE with parenthesized arrow function body is considered unreadable.␊
67+
`
68+
69+
## Invalid #5
70+
1 | const foo = (() => ({
71+
2 | a: b,
72+
3 | }))();
73+
74+
> Error 1/1
75+
76+
`␊
77+
> 1 | const foo = (() => ({␊
78+
| ^^␊
79+
> 2 | a: b,␊
80+
| ^^^^^^␊
81+
> 3 | }))();␊
82+
| ^^^ IIFE with parenthesized arrow function body is considered unreadable.␊
83+
`
84+
85+
## Invalid #6
86+
1 | const foo = (bar => (bar))();
87+
88+
> Error 1/1
89+
90+
`␊
91+
> 1 | const foo = (bar => (bar))();␊
92+
| ^^^^^ IIFE with parenthesized arrow function body is considered unreadable.␊
93+
`
94+
95+
## Invalid #7
96+
1 | (async () => ({
97+
2 | bar,
98+
3 | }))();
99+
100+
> Error 1/1
101+
102+
`␊
103+
> 1 | (async () => ({␊
104+
| ^^␊
105+
> 2 | bar,␊
106+
| ^^^^^␊
107+
> 3 | }))();␊
108+
| ^^^ IIFE with parenthesized arrow function body is considered unreadable.␊
109+
`
110+
111+
## Invalid #8
112+
1 | const foo = (async (bar) => ({
113+
2 | bar: await baz(),
114+
3 | }))();
115+
116+
> Error 1/1
117+
118+
`␊
119+
> 1 | const foo = (async (bar) => ({␊
120+
| ^^␊
121+
> 2 | bar: await baz(),␊
122+
| ^^^^^^^^^^^^^^^^^^␊
123+
> 3 | }))();␊
124+
| ^^^ IIFE with parenthesized arrow function body is considered unreadable.␊
125+
`
126+
127+
## Invalid #9
128+
1 | (async () => (( {bar} )))();
129+
130+
> Error 1/1
131+
132+
`␊
133+
> 1 | (async () => (( {bar} )))();␊
134+
| ^^^^^^^^^^^ IIFE with parenthesized arrow function body is considered unreadable.␊
135+
`
603 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)