Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

New: Adds implicit-arrow-linebreak rule (refs #9510) #9629

Merged
merged 3 commits into from
Nov 26, 2017

Conversation

sharmilajesupaul
Copy link
Contributor

What is the purpose of this pull request? (put an "X" next to item)

  • adds a new rule

What changes did you make? (Give an overview)
Introduces a new rule enforcing the location of arrow function bodies with implicit returns. Also adds tests and docs.
Refs: #9510 & #6067

Is there anything you'd like reviewers to focus on?
I think this rule gets a little less intuitive when it comes to function bodies surrounded by parentheses.

I would like to make sure that this rule never warns on a case where parentheses are used to surround a multiline body, like this:

(foo) => (
  bar
);

However, currently, it does warn on cases like:

// incorrect code for "beside" option
(foo) => 
  (bar);

// incorrect code for "below" option
(foo) => (bar)

I'm not sure if that's the best way to handle this 馃

cc. @ljharb, @not-an-aardvark
more discussion: #9623.

Copy link
Sponsor Contributor

@ljharb ljharb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@aladdin-add aladdin-add added evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion feature This change adds a new feature to ESLint rule Relates to ESLint's core rules labels Nov 16, 2017
@kaicataldo
Copy link
Member

This needs a champion as well as support from one more team member.

Something to note is that this rule is incompatible with arrow-spacing when this rule is configured with "below" and arrow-spacing is configured with { after: false }. Not an issue since there aren't any cases where they don't overlap.

@sharmilajesupaul
Copy link
Contributor Author

@kaicataldo how do I find someone to champion this rule? Should I make an issue with the rule proposal?

@kaicataldo
Copy link
Member

@sharmilajesupaul No need to do anything! Thanks for a great PR.

@eslint/eslint-team Looks like we have support from three team members and just need someone to step up to champion.

@platinumazure platinumazure self-assigned this Nov 18, 2017
@platinumazure
Copy link
Member

I'll champion this. Marking as accepted.

@platinumazure platinumazure added accepted There is consensus among the team that this change meets the criteria for inclusion and removed evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion labels Nov 18, 2017
Copy link
Member

@platinumazure platinumazure left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good to me. My only concern is possible user confusion about whether arrow-linebreak also applies to arrow functions with block statements. Therefore I would like to suggest that some or all of the following changes be considered:

  • Add documentation about which rule would control line breaks around braces (brace-style maybe?)
  • Consider renaming the rule to something like concise-arrow-linebreak or implicit-arrow-linebreak to help make clear that this doesn't apply to non-concise arrow function bodies

Thanks!

@ljharb
Copy link
Sponsor Contributor

ljharb commented Nov 18, 2017

"concise" refers to concise object methods; i'd prefer "implicit".

@platinumazure
Copy link
Member

I've heard it both ways (and I use "shorthand" for those object methods). I'm not going to insist strongly on a name change, but I do think it would help.

@not-an-aardvark
Copy link
Member

brace-style already covers arrow functions with block statements, so I don't think arrow-linebreak should cover them too.

@platinumazure
Copy link
Member

brace-style already covers arrow functions with block statements, so I don't think arrow-linebreak should cover them too.

Agreed full stop. However, the rule name and documentation could confuse a new user into thinking that the rule should cover that scenario (until you read some of the examples, anyway). So it makes sense for a See Also section to reference brace-style for sure. I also think it wouldn't hurt to change the name of the rule to be more precise about exactly what it covers.

Copy link
Member

@not-an-aardvark not-an-aardvark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR! This mostly looks good to me, I just have a few small suggestions.

@@ -0,0 +1,84 @@
# Enforce the location of arrow function bodies with implicit returns (arrow-linebreak)

An arrow function body can contain an implicit return as a single statement instead of a block. It can be useful to enforce a consistent location for the arrow function body.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: The body of implicit-return arrow functions is actually an expression, not a statement.

* @param {string} keywordName The applicable keyword name for the arrow function body
* @returns {void}
*/
function validateStatement(node) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: I think this function should be called something like validateExpression rather than validateStatement, because there aren't any statements being used here.

return bar();
}

(foo) => ( // a function body with a leading parentheses is also always allowed with this rule
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the reasoning for always allowing this? I would have expected that an opening parenthesis on the first line would be treated the same way as anything else on the first line (i.e. allowed with beside, disallowed with below).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review! I originally made this rule to be able to enforce that our code doesn't have lines that end in a =>, but I wanted to make an exception for cases like:

(foo) => (
  bar
);

// &

(foo) => 
  (
    bar
  );

However, I agree with you, treating them the same way will make this rule much clearer. The first case above should be allowed with beside and the second with below. I'll update the logic for this.


if (hasParens) {
fixerTarget = tokenBefore;
tokenBefore = sourceCode.getTokenBefore(fixerTarget);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this won't be correct if the arrow function body is surrounded by multiple sets of parentheses:

var x = foo =>
    ((((bar))));

In that case, tokenBefore will refer to the wrong thing because it will still be an opening paren.

Instead, one option would be to use some thing like

sourceCode.getTokenBefore(node.body, token => token.value !== "(")

...which will get the first token before the body that isn't an opening paren.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, I completely missed this case entirely 馃様 Will make an update soon.

Adds a new rule that enforces consistency of arrow function bodies
that contain an implicit return.
@sharmilajesupaul
Copy link
Contributor Author

Made some improvements:

ptal @not-an-aardvark, @platinumazure, & @ljharb, thanks!

fixerTarget = sourceCode.getTokenAfter(tokenBefore);
}

if (tokenBefore.loc.end.line === fixerTarget.loc.start.line && option === "below") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would check for the option first so that we can short-circuit quicker. Same applies below also

// Public
//----------------------------------------------------------------------
return {
ArrowFunctionExpression: node => validateExpression(node)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

directly use the function here

ArrowFunctionExpression: validateExpression

Copy link
Member

@gyandeeps gyandeeps left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm. thanks.
just 2 nitpicks

Copy link
Member

@not-an-aardvark not-an-aardvark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks good to me. I just have a few minor nitpicks.

Examples of **incorrect** code for this rule with the default `"beside"` option:

```js
/* eslint arrow-linebreak: ["error", "beside"] */
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rule has been renamed to implicit-arrow-linebreak, but this comment still calls it arrow-linebreak. (There are a few other comments like it in this file.)


const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } });

ruleTester.run("arrow-linebreak", rule, {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rule has been renamed to implicit-arrow-linebreak, but this line still calls it arrow-linebreak.

@platinumazure
Copy link
Member

platinumazure commented Nov 25, 2017

@sharmilajesupaul I hope it's okay that I fixed some of the last "arrow-linebreak" references on your branch. Of course I know you were more than capable of doing it, but there's a (slim) chance we might still release this weekend despite the US holiday and I wanted to save you some time. Thanks again for contributing!

EDIT: And I renamed the PR title for the same reason. Thanks for your understanding!

@platinumazure platinumazure changed the title New: Adds arrow-linebreak rule (refs #9510) New: Adds implicit-arrow-linebreak rule (refs #9510) Nov 25, 2017
@not-an-aardvark not-an-aardvark merged commit 4118f14 into eslint:master Nov 26, 2017
@not-an-aardvark
Copy link
Member

Thanks for contributing!

@eslint-deprecated eslint-deprecated bot locked and limited conversation to collaborators May 26, 2018
@eslint-deprecated eslint-deprecated bot added the archived due to age This issue has been archived; please open a new issue for any further discussion label May 26, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
accepted There is consensus among the team that this change meets the criteria for inclusion archived due to age This issue has been archived; please open a new issue for any further discussion feature This change adds a new feature to ESLint rule Relates to ESLint's core rules
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants