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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

no-inner-declarations inconsistency #12222

Closed
mdjermanovic opened this issue Sep 5, 2019 · 14 comments · Fixed by #13062
Closed

no-inner-declarations inconsistency #12222

mdjermanovic opened this issue Sep 5, 2019 · 14 comments · Fixed by #13062
Assignees
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 bug ESLint is working incorrectly rule Relates to ESLint's core rules

Comments

@mdjermanovic
Copy link
Member

Tell us about your environment

  • ESLint Version: 6.3.0
  • Node Version: 10.16.0
  • npm Version: 6.9.0

What parser (default, Babel-ESLint, etc.) are you using?

default

Please show your full configuration:

Configuration
module.exports = {
  parserOptions: {
    ecmaVersion: 2015,
  }
};

What did you do? Please include the actual source code causing the issue, as well as the command that you used to run ESLint.

Demo link

/*eslint no-inner-declarations: ["error", "both"]*/

if (foo)
  var a;

if (foo)
  function f(){}

function bar() {
  if (foo)
    var a;

  if (foo)
    function f(){}
}
eslint index.js

What did you expect to happen?

To be consistent, either 4 errors or no errors?

This rule requires that function declarations and, optionally, variable declarations be in the root of a program or the body of a function.

Are these declarations in the root/body? Also, the documentation is later more specific:

"functions" (default) disallows function declarations in nested blocks

"both" disallows function and var declarations in nested blocks

What actually happened? Please include the actual, raw output from ESLint.

2 errors:

11:5  error  Move variable declaration to function body root  no-inner-declarations
14:5  error  Move function declaration to function body root  no-inner-declarations
/*eslint no-inner-declarations: ["error", "both"]*/

if (foo)
  var a; // no error

if (foo)
  function f(){} // no error

function bar() {
  if (foo)
    var a; // error

  if (foo)
    function f(){} // error
}

Are you willing to submit a pull request to fix this bug?

Yes, if this is confirmed to be a bug.

Perhaps the rule should allow only these places for function and var declaration nodes:

  • Program > node
  • ExportNamedDeclaration > node
  • ExportDefaultDeclaration > node (function only)
  • Function > BlockStatement > node

meaning that there should be 4 errors in the above example, but I'm not sure is this the intention of this rule.

@mdjermanovic mdjermanovic added bug ESLint is working incorrectly triage An ESLint team member will look at this issue soon labels Sep 5, 2019
@aladdin-add aladdin-add added evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion rule Relates to ESLint's core rules and removed triage An ESLint team member will look at this issue soon labels Sep 5, 2019
@platinumazure
Copy link
Member

I would be 👍 for having 4 errors in your example.

@eslint-deprecated eslint-deprecated bot added the auto closed The bot closed this issue label Oct 8, 2019
@eslint-deprecated
Copy link

Unfortunately, it looks like there wasn't enough interest from the team
or community to implement this change. While we wish we'd be able to
accommodate everyone's requests, we do need to prioritize. We've found
that issues failing to reach accepted status after 21 days tend to
never be accepted, and as such, we close those issues.
This doesn't mean the idea isn't interesting or useful, just that it's
not something the team can commit to.

Thanks for contributing to ESLint and we appreciate your understanding.

@kaicataldo
Copy link
Member

This looks like a bug to me - reopening so we can evaluate.

@kaicataldo kaicataldo reopened this Oct 9, 2019
@kaicataldo kaicataldo added accepted There is consensus among the team that this change meets the criteria for inclusion needs bikeshedding Minor details about this change need to be discussed and removed auto closed The bot closed this issue evaluating The team will evaluate this issue to decide whether it meets the criteria for inclusion labels Oct 9, 2019
@eslint-deprecated eslint-deprecated bot added the auto closed The bot closed this issue label Dec 5, 2019
@eslint-deprecated
Copy link

Unfortunately, it looks like there wasn't enough interest from the team
or community to implement this change. While we wish we'd be able to
accommodate everyone's requests, we do need to prioritize. We've found
that accepted issues failing to be implemented after 90 days tend to
never be implemented, and as such, we close those issues.
This doesn't mean the idea isn't interesting or useful, just that it's
not something the team can commit to.

Thanks for contributing to ESLint and we appreciate your understanding.

@mdjermanovic mdjermanovic self-assigned this Dec 5, 2019
@mdjermanovic mdjermanovic removed the auto closed The bot closed this issue label Dec 5, 2019
@mdjermanovic mdjermanovic reopened this Dec 5, 2019
@anikethsaha
Copy link
Member

anikethsaha commented Mar 18, 2020

@mdjermanovic when wrapping the if statement blocks with parens { } , all are showing errors

/*eslint no-inner-declarations: ["error", "both"]*/

if (foo){
  var a; // error
}

if (foo){
  function f(){}  // error
}

function bar() {
  if (foo)
    var a;  // error

  if (foo){
    function f(){}  // error
  }
}

demo

@anikethsaha
Copy link
Member

anikethsaha commented Mar 18, 2020

BlockStatement > VariableDeclaration should be check as well

@anikethsaha
Copy link
Member

anikethsaha commented Mar 18, 2020

@mdjermanovic I have a fix working for this! mind if I submit the change?

here is the fix anikethsaha@83f83c5

anikethsaha added a commit to anikethsaha/eslint that referenced this issue Mar 18, 2020
@mdjermanovic
Copy link
Member Author

@anikethsaha Sure, thanks!

It isn't entirely clear what should be done, but it looks like a good idea to continue the discussion on a PR.

@kaicataldo
Copy link
Member

@mdjermanovic @anikethsaha Could one of you sum up what needs to be discussed here so that the rest of the team can easily provide input?

@mdjermanovic
Copy link
Member Author

The question is should we change the logic to report all declarations except those that have either:

  • Program parent
  • ExportNamedDeclaration parent
  • ExportDefaultDeclaration parent
  • BlockStatement parent and FunctionDeclaration grandparent
  • BlockStatement parent and FunctionExpression grandparent
  • BlockStatement parent and ArrowFunctionExpression grandparent

In particular, cases like these would be new warnings:

if (foo)
  var a; 

if (foo)
  function f(){}

while (foo)
  var a; 

@kaicataldo
Copy link
Member

Understood. I think there should be no errors in the original example since the documentation specifically refers to blocks. This feels especially true with lexically scoped variable declarations, since the actual scope would change.

@mdjermanovic
Copy link
Member Author

mdjermanovic commented Mar 26, 2020

I believe there are no lexically scoped variable declarations in those cases.

if (foo) function f(){} is allowed only by Annex B (B.3.4)

In strict mode, it's a syntax error.

In non-strict mode, it's treated as if it was if (foo) { function f(){} }, which by B.3.3 isn't lexically scoped in non-strict mode.

/* not strict */

f; // doesn't throw ReferenceError

console.log(typeof f); // undefined, isn't intialized yet

if (true)
    function f() { return 33; }

console.log(f()); // 33


g; // doesn't throw ReferenceError

console.log(typeof g); // undefined, isn't intialized yet

if (true) {
    function g() { return 55; }
}

console.log(g()); // 55

If this rule shouldn't report if (foo) function f(){} by default, then it would be useful to have an option or another rule for that, since it's a legacy Annex B feature with a confusing behavior.

@kaicataldo
Copy link
Member

I believe there are no lexically scoped variable declarations in those cases.

Ah, you're right. Thanks for explaining this. I agree with you that this should have 4 errors. 👍

@kaicataldo kaicataldo removed the needs bikeshedding Minor details about this change need to be discussed label Mar 30, 2020
@kaicataldo
Copy link
Member

Given three team members (@platinumazure, @mdjermanovic, and myself) believe this should have 4 errors, I think we can confidently move forward here. Removing the "needs bikeshedding" label.

nzakas pushed a commit that referenced this issue Mar 31, 2020
…) (#13062)

* Fix: consistencies for blockstmt no-inner-fn (fix #12222)

* Chore: added some more tests

* Chore: allowing named and default exports and tests

* Chore: simply the check conditions

* Chore: simplify checks and ancestor loop

* Chore: using getUpperFunction to get body

* chore: added tests and minor changes

* Docs: eg for both non-blockstatement

* Chore: right docs example and test refactore
@eslint-deprecated eslint-deprecated bot locked and limited conversation to collaborators Sep 28, 2020
@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 Sep 28, 2020
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 bug ESLint is working incorrectly rule Relates to ESLint's core rules
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants