Skip to content

Commit

Permalink
fix: update vars-on-top for class static blocks (#15306)
Browse files Browse the repository at this point in the history
Fixes the `vars-on-top` rule to allow `var` declarations at the top of class static blocks.

Refs #15016
  • Loading branch information
mdjermanovic committed Nov 21, 2021
1 parent 479a4cb commit 8aa7645
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 16 deletions.
50 changes: 46 additions & 4 deletions docs/rules/vars-on-top.md
Expand Up @@ -14,11 +14,10 @@ Examples of **incorrect** code for this rule:
```js
/*eslint vars-on-top: "error"*/

// Variable declarations in a block:
// Variable declaration in a nested block, and a variable declaration after other statements:
function doSomething() {
var first;
if (true) {
first = true;
var first = true;
}
var second;
}
Expand All @@ -32,11 +31,34 @@ function doSomething() {
```js
/*eslint vars-on-top: "error"*/

// Variables after other statements:
// Variable declaration after other statements:
f();
var a;
```

```js
/*eslint vars-on-top: "error"*/

// Variables in class static blocks should be at the top of the static blocks.

class C {

// Variable declaration in a nested block:
static {
if (something) {
var a = true;
}
}

// Variable declaration after other statements:
static {
f();
var a;
}

}
```

Examples of **correct** code for this rule:

```js
Expand Down Expand Up @@ -66,6 +88,26 @@ f();
```js
/*eslint vars-on-top: "error"*/

class C {

static {
var a;
if (something) {
a = true;
}
}

static {
var a;
f();
}

}
```

```js
/*eslint vars-on-top: "error"*/

// Directives may precede variable declarations.
"use strict";
var a;
Expand Down
37 changes: 25 additions & 12 deletions lib/rules/vars-on-top.js
Expand Up @@ -77,10 +77,12 @@ module.exports = {
const l = statements.length;
let i = 0;

// skip over directives
for (; i < l; ++i) {
if (!looksLikeDirective(statements[i]) && !looksLikeImport(statements[i])) {
break;
// Skip over directives and imports. Static blocks don't have either.
if (node.parent.type !== "StaticBlock") {
for (; i < l; ++i) {
if (!looksLikeDirective(statements[i]) && !looksLikeImport(statements[i])) {
break;
}
}
}

Expand Down Expand Up @@ -111,16 +113,27 @@ module.exports = {
/**
* Checks whether variable is on top at functional block scope level
* @param {ASTNode} node The node to check
* @param {ASTNode} parent Parent of the node
* @param {ASTNode} grandParent Parent of the node's parent
* @returns {void}
*/
function blockScopeVarCheck(node, parent, grandParent) {
if (!(/Function/u.test(grandParent.type) &&
parent.type === "BlockStatement" &&
isVarOnTop(node, parent.body))) {
context.report({ node, messageId: "top" });
function blockScopeVarCheck(node) {
const { parent } = node;

if (
parent.type === "BlockStatement" &&
/Function/u.test(parent.parent.type) &&
isVarOnTop(node, parent.body)
) {
return;
}

if (
parent.type === "StaticBlock" &&
isVarOnTop(node, parent.body)
) {
return;
}

context.report({ node, messageId: "top" });
}

//--------------------------------------------------------------------------
Expand All @@ -134,7 +147,7 @@ module.exports = {
} else if (node.parent.type === "Program") {
globalVarCheck(node, node.parent);
} else {
blockScopeVarCheck(node, node.parent, node.parent.parent);
blockScopeVarCheck(node);
}
}
};
Expand Down
150 changes: 150 additions & 0 deletions tests/lib/rules/vars-on-top.js
Expand Up @@ -191,6 +191,84 @@ ruleTester.run("vars-on-top", rule, {
ecmaVersion: 6,
sourceType: "module"
}
},
{
code: [
"class C {",
" static {",
" var x;",
" }",
"}"
].join("\n"),
parserOptions: {
ecmaVersion: 2022
}
},
{
code: [
"class C {",
" static {",
" var x;",
" foo();",
" }",
"}"
].join("\n"),
parserOptions: {
ecmaVersion: 2022
}
},
{
code: [
"class C {",
" static {",
" var x;",
" var y;",
" }",
"}"
].join("\n"),
parserOptions: {
ecmaVersion: 2022
}
},
{
code: [
"class C {",
" static {",
" var x;",
" var y;",
" foo();",
" }",
"}"
].join("\n"),
parserOptions: {
ecmaVersion: 2022
}
},
{
code: [
"class C {",
" static {",
" let x;",
" var y;",
" }",
"}"
].join("\n"),
parserOptions: {
ecmaVersion: 2022
}
},
{
code: [
"class C {",
" static {",
" foo();",
" let x;",
" }",
"}"
].join("\n"),
parserOptions: {
ecmaVersion: 2022
}
}
],

Expand Down Expand Up @@ -427,6 +505,78 @@ ruleTester.run("vars-on-top", rule, {
sourceType: "module"
},
errors: [error]
},
{
code: [
"class C {",
" static {",
" foo();",
" var x;",
" }",
"}"
].join("\n"),
parserOptions: {
ecmaVersion: 2022
},
errors: [error]
},
{
code: [
"class C {",
" static {",
" 'use strict';", // static blocks do not have directives
" var x;",
" }",
"}"
].join("\n"),
parserOptions: {
ecmaVersion: 2022
},
errors: [error]
},
{
code: [
"class C {",
" static {",
" var x;",
" foo();",
" var y;",
" }",
"}"
].join("\n"),
parserOptions: {
ecmaVersion: 2022
},
errors: [{ ...error, line: 5 }]
},
{
code: [
"class C {",
" static {",
" if (foo) {",
" var x;",
" }",
" }",
"}"
].join("\n"),
parserOptions: {
ecmaVersion: 2022
},
errors: [error]
},
{
code: [
"class C {",
" static {",
" if (foo)",
" var x;",
" }",
"}"
].join("\n"),
parserOptions: {
ecmaVersion: 2022
},
errors: [error]
}
]
});

0 comments on commit 8aa7645

Please sign in to comment.