-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* New: Adds implicit-arrow-linebreak rule (refs #9510) Adds a new rule that enforces consistency of arrow function bodies that contain an implicit return. * Docs: Use "implicit-arrow-linebreak" consistently * Chore: Use name "implicit-arrow-linebreak"
- Loading branch information
1 parent
208fb0f
commit 4118f14
Showing
4 changed files
with
361 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# Enforce the location of arrow function bodies with implicit returns (implicit-arrow-linebreak) | ||
|
||
An arrow function body can contain an implicit return as an expression instead of a block body. It can be useful to enforce a consistent location for the implicitly returned expression. | ||
|
||
## Rule Details | ||
|
||
This rule aims to enforce a consistent location for an arrow function containing an implicit return. | ||
|
||
See Also: | ||
|
||
- [`brace-style`](https://eslint.org/docs/rules/brace-style) which enforces this behavior for arrow functions with block bodies. | ||
|
||
### Options | ||
|
||
This rule accepts a string option: | ||
|
||
- `"beside"` (default) disallows a newline before an arrow function body. | ||
- `"below"` requires a newline before an arrow function body. | ||
|
||
Examples of **incorrect** code for this rule with the default `"beside"` option: | ||
|
||
```js | ||
/* eslint implicit-arrow-linebreak: ["error", "beside"] */ | ||
|
||
(foo) => | ||
bar; | ||
|
||
(foo) => | ||
(bar); | ||
|
||
(foo) => | ||
bar => | ||
baz; | ||
|
||
(foo) => | ||
( | ||
bar() | ||
); | ||
``` | ||
|
||
Examples of **correct** code for this rule with the default `"beside"` option: | ||
|
||
```js | ||
/* eslint implicit-arrow-linebreak: ["error", "beside"] */ | ||
|
||
(foo) => bar; | ||
|
||
(foo) => (bar); | ||
|
||
(foo) => bar => baz; | ||
|
||
(foo) => ( | ||
bar() | ||
); | ||
|
||
// functions with block bodies allowed with this rule using any style | ||
// to enforce a consistent location for this case, see the rule: `brace-style` | ||
(foo) => { | ||
return bar(); | ||
} | ||
|
||
(foo) => | ||
{ | ||
return bar(); | ||
} | ||
``` | ||
|
||
Examples of **incorrect** code for this rule with the `"below"` option: | ||
|
||
```js | ||
/* eslint implicit-arrow-linebreak: ["error", "below"] */ | ||
|
||
(foo) => bar; | ||
|
||
(foo) => (bar); | ||
|
||
(foo) => bar => baz; | ||
``` | ||
|
||
Examples of **correct** code for this rule with the `"below"` option: | ||
|
||
```js | ||
/* eslint implicit-arrow-linebreak: ["error", "below"] */ | ||
|
||
|
||
(foo) => | ||
bar; | ||
|
||
(foo) => | ||
(bar); | ||
|
||
(foo) => | ||
bar => | ||
baz; | ||
``` | ||
|
||
## When Not To Use It | ||
|
||
If you're not concerned about consistent locations of implicitly returned arrow function expressions, you should not turn on this rule. | ||
|
||
You can also disable this rule if you are using the `"always"` option for the [`arrow-body-style`](https://eslint.org/docs/rules/arrow-body-style), since this will disable the use of implicit returns in arrow functions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
/** | ||
* @fileoverview enforce the location of arrow function bodies | ||
* @author Sharmila Jesupaul | ||
*/ | ||
"use strict"; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Rule Definition | ||
//------------------------------------------------------------------------------ | ||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: "enforce the location of arrow function bodies", | ||
category: "Stylistic Issues", | ||
recommended: false | ||
}, | ||
fixable: "whitespace", | ||
schema: [ | ||
{ | ||
enum: ["beside", "below"] | ||
} | ||
] | ||
}, | ||
|
||
create(context) { | ||
const sourceCode = context.getSourceCode(); | ||
|
||
//---------------------------------------------------------------------- | ||
// Helpers | ||
//---------------------------------------------------------------------- | ||
/** | ||
* Gets the applicable preference for a particular keyword | ||
* @returns {string} The applicable option for the keyword, e.g. 'beside' | ||
*/ | ||
function getOption() { | ||
return context.options[0] || "beside"; | ||
} | ||
|
||
/** | ||
* Validates the location of an arrow function body | ||
* @param {ASTNode} node The arrow function body | ||
* @param {string} keywordName The applicable keyword name for the arrow function body | ||
* @returns {void} | ||
*/ | ||
function validateExpression(node) { | ||
const option = getOption(); | ||
|
||
let tokenBefore = sourceCode.getTokenBefore(node.body); | ||
const hasParens = tokenBefore.value === "("; | ||
|
||
if (node.type === "BlockStatement") { | ||
return; | ||
} | ||
|
||
let fixerTarget = node.body; | ||
|
||
if (hasParens) { | ||
|
||
// Gets the first token before the function body that is not an open paren | ||
tokenBefore = sourceCode.getTokenBefore(node.body, token => token.value !== "("); | ||
fixerTarget = sourceCode.getTokenAfter(tokenBefore); | ||
} | ||
|
||
if (tokenBefore.loc.end.line === fixerTarget.loc.start.line && option === "below") { | ||
context.report({ | ||
node: fixerTarget, | ||
message: "Expected a linebreak before this expression.", | ||
fix: fixer => fixer.insertTextBefore(fixerTarget, "\n") | ||
}); | ||
} else if (tokenBefore.loc.end.line !== fixerTarget.loc.start.line && option === "beside") { | ||
context.report({ | ||
node: fixerTarget, | ||
message: "Expected no linebreak before this expression.", | ||
fix: fixer => fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " ") | ||
}); | ||
} | ||
} | ||
|
||
//---------------------------------------------------------------------- | ||
// Public | ||
//---------------------------------------------------------------------- | ||
return { | ||
ArrowFunctionExpression: node => validateExpression(node) | ||
}; | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
/** | ||
* @fileoverview enforce the location of arrow function bodies | ||
* @author Sharmila Jesupaul | ||
*/ | ||
"use strict"; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Requirements | ||
//------------------------------------------------------------------------------ | ||
|
||
const rule = require("../../../lib/rules/implicit-arrow-linebreak"); | ||
const RuleTester = require("../../../lib/testers/rule-tester"); | ||
|
||
const EXPECTED_LINEBREAK = { message: "Expected a linebreak before this expression." }; | ||
const UNEXPECTED_LINEBREAK = { message: "Expected no linebreak before this expression." }; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Tests | ||
//------------------------------------------------------------------------------ | ||
|
||
const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); | ||
|
||
ruleTester.run("implicit-arrow-linebreak", rule, { | ||
|
||
valid: [ | ||
|
||
// always valid | ||
`(foo) => { | ||
bar | ||
}`, | ||
|
||
// 'beside' option | ||
"() => bar;", | ||
"() => (bar);", | ||
"() => bar => baz;", | ||
"() => ((((bar))));", | ||
`(foo) => ( | ||
bar | ||
)`, | ||
{ | ||
code: "(foo) => bar();", | ||
options: ["beside"] | ||
}, | ||
|
||
// 'below' option | ||
{ | ||
code: ` | ||
(foo) => | ||
( | ||
bar | ||
) | ||
`, | ||
options: ["below"] | ||
}, { | ||
code: ` | ||
() => | ||
((((bar)))); | ||
`, | ||
options: ["below"] | ||
}, { | ||
code: ` | ||
() => | ||
bar(); | ||
`, | ||
options: ["below"] | ||
}, { | ||
code: ` | ||
() => | ||
(bar); | ||
`, | ||
options: ["below"] | ||
}, { | ||
code: ` | ||
() => | ||
bar => | ||
baz; | ||
`, | ||
options: ["below"] | ||
} | ||
], | ||
|
||
invalid: [ | ||
|
||
// 'beside' option | ||
{ | ||
code: ` | ||
(foo) => | ||
bar(); | ||
`, | ||
output: ` | ||
(foo) => bar(); | ||
`, | ||
errors: [UNEXPECTED_LINEBREAK] | ||
}, { | ||
code: ` | ||
() => | ||
(bar); | ||
`, | ||
output: ` | ||
() => (bar); | ||
`, | ||
errors: [UNEXPECTED_LINEBREAK] | ||
}, { | ||
code: ` | ||
() => | ||
bar => | ||
baz; | ||
`, | ||
output: ` | ||
() => bar => baz; | ||
`, | ||
errors: [UNEXPECTED_LINEBREAK, UNEXPECTED_LINEBREAK] | ||
}, { | ||
code: ` | ||
() => | ||
((((bar)))); | ||
`, | ||
output: ` | ||
() => ((((bar)))); | ||
`, | ||
errors: [UNEXPECTED_LINEBREAK] | ||
}, { | ||
code: ` | ||
(foo) => | ||
( | ||
bar | ||
) | ||
`, | ||
output: ` | ||
(foo) => ( | ||
bar | ||
) | ||
`, | ||
errors: [UNEXPECTED_LINEBREAK] | ||
}, | ||
|
||
// 'below' option | ||
{ | ||
code: "(foo) => bar();", | ||
output: "(foo) => \nbar();", | ||
options: ["below"], | ||
errors: [EXPECTED_LINEBREAK] | ||
}, { | ||
code: "(foo) => bar => baz;", | ||
output: "(foo) => \nbar => \nbaz;", | ||
options: ["below"], | ||
errors: [EXPECTED_LINEBREAK, EXPECTED_LINEBREAK] | ||
}, { | ||
code: "(foo) => (bar);", | ||
output: "(foo) => \n(bar);", | ||
options: ["below"], | ||
errors: [EXPECTED_LINEBREAK] | ||
}, { | ||
code: "(foo) => (((bar)));", | ||
output: "(foo) => \n(((bar)));", | ||
options: ["below"], | ||
errors: [EXPECTED_LINEBREAK] | ||
}, { | ||
code: ` | ||
(foo) => ( | ||
bar | ||
) | ||
`, | ||
output: ` | ||
(foo) => \n( | ||
bar | ||
) | ||
`, | ||
options: ["below"], | ||
errors: [EXPECTED_LINEBREAK] | ||
} | ||
] | ||
}); |