Skip to content

Commit a86fe5e

Browse files
authored
Add consistent-function-style rule (#3137)
1 parent 8d81f7e commit a86fe5e

12 files changed

Lines changed: 1442 additions & 21 deletions
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# consistent-function-style
2+
3+
📝 Enforce function syntax by role.
4+
5+
🚫 This rule is _disabled_ in the following [configs](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config): ✅ `recommended`, ☑️ `unopinionated`.
6+
7+
💡 This rule is manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions).
8+
9+
<!-- end auto-generated rule header -->
10+
<!-- Do not manually modify this header. Run: `npm run fix:eslint-docs` -->
11+
12+
Enforce function syntax by role.
13+
14+
By default, this rule reports nothing. Configure the roles you want to enforce.
15+
16+
This rule does not autofix. Function declarations, function expressions, arrow functions, and object methods are not always semantic equivalents, so `--fix` would be too risky for a style rule.
17+
18+
The rule offers editor suggestions only for simple callback conversions between anonymous function expressions and arrow functions. Suggestions are skipped when the callback contains comments, `this`, `arguments`, `super`, `new.target`, direct `eval()`, generators, named function expressions, or TypeScript type parameters.
19+
20+
## Examples
21+
22+
```js
23+
// eslint unicorn/consistent-function-style: ["error", {namedFunctions: "declaration"}]
24+
25+
//
26+
const parse = value => value;
27+
28+
//
29+
function parse(value) {
30+
return value;
31+
}
32+
```
33+
34+
```js
35+
// ✅ Reassigned variables are ignored by default.
36+
let transform = value => value;
37+
38+
if (debug) {
39+
transform = wrap(transform);
40+
}
41+
```
42+
43+
```js
44+
// ✅ Callbacks are ignored by default.
45+
items.map(item => item.id);
46+
```
47+
48+
## Options
49+
50+
Type: `object`
51+
52+
Default:
53+
54+
```js
55+
{
56+
default: 'ignore',
57+
namedFunctions: 'ignore',
58+
namedExports: 'ignore',
59+
callbacks: 'ignore',
60+
objectProperties: 'ignore',
61+
reassignedVariables: 'ignore',
62+
typedVariables: 'ignore',
63+
}
64+
```
65+
66+
Each option chooses the expected style for a role.
67+
68+
When multiple roles apply, the most specific role wins. Roles are checked in this order:
69+
70+
```js
71+
typedVariables
72+
reassignedVariables
73+
namedExports
74+
callbacks
75+
objectProperties
76+
namedFunctions
77+
default
78+
```
79+
80+
### `default`
81+
82+
Allowed values: `'declaration'`, `'function-expression'`, `'arrow-function'`, `'ignore'`
83+
84+
Fallback style for functions that do not match a more specific role.
85+
86+
### `namedFunctions`
87+
88+
Allowed values: `'declaration'`, `'function-expression'`, `'arrow-function'`, `'ignore'`
89+
90+
Style for function declarations and named variable functions.
91+
92+
### `namedExports`
93+
94+
Allowed values: `'declaration'`, `'function-expression'`, `'arrow-function'`, `'ignore'`
95+
96+
Style for inline named function exports, such as `export function foo() {}` and `export const foo = () => {}`. Export specifier lists like `export {foo}` are ignored.
97+
98+
### `callbacks`
99+
100+
Allowed values: `'function-expression'`, `'arrow-function'`, `'ignore'`
101+
102+
Style for inline functions passed as call or constructor arguments.
103+
104+
### `objectProperties`
105+
106+
Allowed values: `'method'`, `'function-expression'`, `'arrow-function'`, `'ignore'`
107+
108+
Style for object literal function properties.
109+
110+
### `reassignedVariables`
111+
112+
Allowed values: `'function-expression'`, `'arrow-function'`, `'ignore'`
113+
114+
Style for variable functions whose binding is reassigned after initialization.
115+
116+
### `typedVariables`
117+
118+
Allowed values: `'function-expression'`, `'arrow-function'`, `'ignore'`
119+
120+
Style for TypeScript variable functions with an explicit type annotation.
121+
122+
## Limitations
123+
124+
The rule ignores anonymous default exports, export specifier lists, IIFEs, accessors, class methods, class fields, destructuring defaults, TypeScript overload declarations, and generators when the expected style is `'arrow-function'`. Most reports do not have suggestions, because the safe rewrite surface is intentionally narrow.

docs/rules/no-subtraction-comparison.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,6 @@ if (a === b) {}
4949

5050
## Caveats
5151

52-
The rewrite is only behavior-preserving for numbers, so it is auto-fixed only when both operands are known to be numbers. For example, `"10" - "5" > 0` is `true`, but `"10" > "5"` is `false`, since strings compare lexicographically. When the operands are not provably numbers, the rule offers a suggestion instead of an auto-fix.
52+
The rewrite is only behavior-preserving for numbers. For example, `"10" - "5" > 0` is `true`, but `"10" > "5"` is `false`, since strings compare lexicographically. The rule auto-fixes strict ordering comparisons (`>` and `<`) when both operands are known to be numbers. For non-strict ordering and equality comparisons, it auto-fixes only when both operands are statically known finite numbers. Otherwise, the rule offers a suggestion instead of an auto-fix.
5353

54-
There is also a numeric edge case the rule does not special-case: when both operands are the same infinity, `Infinity - Infinity` is `NaN`, so `Infinity - Infinity >= 0` is `false` while `Infinity >= Infinity` is `true`.
54+
The extra restriction for non-strict ordering and equality comparisons avoids the infinity edge case: `Infinity - Infinity` is `NaN`, so `Infinity - Infinity >= 0` is `false` while `Infinity >= Infinity` is `true`.

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export default [
7171
| [consistent-empty-array-spread](docs/rules/consistent-empty-array-spread.md) | Prefer consistent types when spreading a ternary in an array literal. || 🔧 | |
7272
| [consistent-existence-index-check](docs/rules/consistent-existence-index-check.md) | Enforce consistent style for element existence checks with `indexOf()`, `lastIndexOf()`, `findIndex()`, and `findLastIndex()`. | ✅ ☑️ | 🔧 | |
7373
| [consistent-function-scoping](docs/rules/consistent-function-scoping.md) | Move function definitions to the highest possible scope. || | |
74+
| [consistent-function-style](docs/rules/consistent-function-style.md) | Enforce function syntax by role. | | | 💡 |
7475
| [consistent-json-file-read](docs/rules/consistent-json-file-read.md) | Enforce consistent JSON file reads before `JSON.parse()`. || 🔧 | |
7576
| [consistent-template-literal-escape](docs/rules/consistent-template-literal-escape.md) | Enforce consistent style for escaping `${` in template literals. || 🔧 | |
7677
| [custom-error-definition](docs/rules/custom-error-definition.md) | Enforce correct `Error` subclassing. | | 🔧 | |

0 commit comments

Comments
 (0)