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

Update: no-inner-declarations false negative in non-block (fixes #12222) #13062

Merged
merged 10 commits into from Mar 31, 2020
9 changes: 9 additions & 0 deletions docs/rules/no-inner-declarations.md
Expand Up @@ -81,6 +81,8 @@ function doSomethingElse() {
function doAnotherThing() { }
}
}

if (foo) function f(){}
```

Examples of **correct** code for this rule with the default `"functions"` option:
Expand All @@ -102,6 +104,8 @@ var fn;
if (test) {
fn = function fnExpression() { };
}

if (foo) var a;
```

### both
Expand All @@ -120,6 +124,11 @@ function doAnotherThing() {
var bar = 81;
}
}


if (foo) var a;

if (foo) function f(){}
```

Examples of **correct** code for this rule with the `"both"` option:
Expand Down
70 changes: 31 additions & 39 deletions lib/rules/no-inner-declarations.js
Expand Up @@ -5,10 +5,19 @@

"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const astUtils = require("./utils/ast-utils");

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

const validParent = new Set(["Program", "ExportNamedDeclaration", "ExportDefaultDeclaration"]);
const validBlockStatementParent = new Set(["FunctionDeclaration", "FunctionExpression", "ArrowFunctionExpression"]);

module.exports = {
meta: {
type: "problem",
Expand All @@ -33,54 +42,37 @@ module.exports = {

create(context) {

/**
* Find the nearest Program or Function ancestor node.
* @returns {Object} Ancestor's type and distance from node.
*/
function nearestBody() {
const ancestors = context.getAncestors();
let ancestor = ancestors.pop(),
generation = 1;

while (ancestor && ["Program", "FunctionDeclaration",
"FunctionExpression", "ArrowFunctionExpression"
].indexOf(ancestor.type) < 0) {
generation += 1;
ancestor = ancestors.pop();
}

return {

// Type of containing ancestor
type: ancestor.type,

// Separation between ancestor and node
distance: generation
};
}

/**
* Ensure that a given node is at a program or function body's root.
* @param {ASTNode} node Declaration node to check.
* @returns {void}
*/
function check(node) {
const body = nearestBody(),
valid = ((body.type === "Program" && body.distance === 1) ||
body.distance === 2);

if (!valid) {
context.report({
node,
messageId: "moveDeclToRoot",
data: {
type: (node.type === "FunctionDeclaration" ? "function" : "variable"),
body: (body.type === "Program" ? "program" : "function body")
}
});
const parent = node.parent;

if (
parent.type === "BlockStatement" && validBlockStatementParent.has(parent.parent.type)
) {
return;
}

if (validParent.has(parent.type)) {
return;
}

const upperFunction = astUtils.getUpperFunction(parent);

context.report({
node,
messageId: "moveDeclToRoot",
data: {
type: (node.type === "FunctionDeclaration" ? "function" : "variable"),
body: (upperFunction === null ? "program" : "function body")
}
});
}


return {

FunctionDeclaration: check,
Expand Down