From 1a1bb4b1ee87c1b33f2d86ef70b3d81e83377547 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Wed, 17 Nov 2021 02:33:28 +0100 Subject: [PATCH] feat: update one-var for class static blocks (#15317) Fixes false positives of the `one-var` rule with option `"always"` where the rule suggests combining declarations from a class static block with declarations from the upper scope. Also enables autofixing declarations at the top level of class static blocks with option `"never"`. Refs #15016 --- docs/rules/one-var.md | 85 +++++++++++- lib/rules/one-var.js | 6 +- tests/lib/rules/one-var.js | 260 +++++++++++++++++++++++++++++++++++++ 3 files changed, 343 insertions(+), 8 deletions(-) diff --git a/docs/rules/one-var.md b/docs/rules/one-var.md index 3c964c4a4fd..df7ee1f60d5 100644 --- a/docs/rules/one-var.md +++ b/docs/rules/one-var.md @@ -66,7 +66,6 @@ Examples of **incorrect** code for this rule with the default `"always"` option: ```js /*eslint one-var: ["error", "always"]*/ -/*eslint-env es6*/ function foo() { var bar; @@ -89,13 +88,31 @@ function foo() { var qux = true; } } + +class C { + static { + var foo; + var bar; + } + + static { + var foo; + if (bar) { + var baz = true; + } + } + + static { + let foo; + let bar; + } +} ``` Examples of **correct** code for this rule with the default `"always"` option: ```js /*eslint one-var: ["error", "always"]*/ -/*eslint-env es6*/ function foo() { var bar, @@ -127,6 +144,30 @@ function foo(){ let qux; } } + +class C { + static { + var foo, bar; + } + + static { + var foo, baz; + if (bar) { + baz = true; + } + } + + static { + let foo, bar; + } + + static { + let foo; + if (bar) { + let baz; + } + } +} ``` ### never @@ -135,7 +176,6 @@ Examples of **incorrect** code for this rule with the `"never"` option: ```js /*eslint one-var: ["error", "never"]*/ -/*eslint-env es6*/ function foo() { var bar, @@ -157,13 +197,19 @@ function foo(){ let bar = true, baz = false; } + +class C { + static { + var foo, bar; + let baz, qux; + } +} ``` Examples of **correct** code for this rule with the `"never"` option: ```js /*eslint one-var: ["error", "never"]*/ -/*eslint-env es6*/ function foo() { var bar; @@ -185,6 +231,15 @@ function foo() { let qux = true; } } + +class C { + static { + var foo; + var bar; + let baz; + let qux; + } +} ``` ### consecutive @@ -193,7 +248,6 @@ Examples of **incorrect** code for this rule with the `"consecutive"` option: ```js /*eslint one-var: ["error", "consecutive"]*/ -/*eslint-env es6*/ function foo() { var bar; @@ -209,14 +263,21 @@ function foo(){ var qux = 3; var quux; } + +class C { + static { + var foo; + var bar; + let baz; + let qux; + } +} ``` Examples of **correct** code for this rule with the `"consecutive"` option: ```js /*eslint one-var: ["error", "consecutive"]*/ -/*eslint-env es6*/ - function foo() { var bar, @@ -232,6 +293,16 @@ function foo(){ var qux = 3, quux; } + +class C { + static { + var foo, bar; + let baz, qux; + doSomething(); + let quux; + var quuux; + } +} ``` ### var, let, and const diff --git a/lib/rules/one-var.js b/lib/rules/one-var.js index 9c78ef87da8..daff2d22b15 100644 --- a/lib/rules/one-var.js +++ b/lib/rules/one-var.js @@ -541,6 +541,8 @@ module.exports = { FunctionDeclaration: startFunction, FunctionExpression: startFunction, ArrowFunctionExpression: startFunction, + StaticBlock: startFunction, // StaticBlock creates a new scope for `var` variables + BlockStatement: startBlock, ForStatement: startBlock, ForInStatement: startBlock, @@ -552,10 +554,12 @@ module.exports = { "ForInStatement:exit": endBlock, "SwitchStatement:exit": endBlock, "BlockStatement:exit": endBlock, + "Program:exit": endFunction, "FunctionDeclaration:exit": endFunction, "FunctionExpression:exit": endFunction, - "ArrowFunctionExpression:exit": endFunction + "ArrowFunctionExpression:exit": endFunction, + "StaticBlock:exit": endFunction }; } diff --git a/tests/lib/rules/one-var.js b/tests/lib/rules/one-var.js index b7ed534380a..935c464b3d0 100644 --- a/tests/lib/rules/one-var.js +++ b/tests/lib/rules/one-var.js @@ -493,6 +493,143 @@ ruleTester.run("one-var", rule, { { code: "var foo = 1;\nlet bar = function() { var x; };\nvar baz = 2;", options: [{ var: "never" }] + }, + + // class static blocks + { + code: "class C { static { var a; let b; const c = 0; } }", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "const a = 0; class C { static { const b = 0; } }", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { const b = 0; } } const a = 0; ", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "let a; class C { static { let b; } }", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let b; } } let a;", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "var a; class C { static { var b; } }", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { var b; } } var a; ", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "var a; class C { static { if (foo) { var b; } } }", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { if (foo) { var b; } } } var a; ", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { const a = 0; if (foo) { const b = 0; } } }", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let a; if (foo) { let b; } } }", + options: ["always"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { const a = 0; const b = 0; } }", + options: ["never"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let a; let b; } }", + options: ["never"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { var a; var b; } }", + options: ["never"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let a; foo; let b; } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let a; const b = 0; let c; } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { var a; foo; var b; } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { var a; let b; var c; } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let a; if (foo) { let b; } } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { if (foo) { let b; } let a; } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { const a = 0; if (foo) { const b = 0; } } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { if (foo) { const b = 0; } const a = 0; } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { var a; if (foo) var b; } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { if (foo) var b; var a; } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { if (foo) { var b; } var a; } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let a; let b = 0; } }", + options: [{ initialized: "consecutive" }], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { var a; var b = 0; } }", + options: [{ initialized: "consecutive" }], + parserOptions: { ecmaVersion: 2022 } } ], invalid: [ @@ -2118,6 +2255,129 @@ ruleTester.run("one-var", rule, { data: { type: "var" }, type: "VariableDeclaration" }] + }, + + // class static blocks + { + code: "class C { static { let x, y; } }", + output: "class C { static { let x; let y; } }", + options: ["never"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ + messageId: "split", + data: { type: "let" }, + type: "VariableDeclaration" + }] + }, + { + code: "class C { static { var x, y; } }", + output: "class C { static { var x; var y; } }", + options: ["never"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ + messageId: "split", + data: { type: "var" }, + type: "VariableDeclaration" + }] + }, + { + code: "class C { static { let x; let y; } }", + output: "class C { static { let x, y; } }", + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ + messageId: "combine", + data: { type: "let" }, + type: "VariableDeclaration" + }] + }, + { + code: "class C { static { var x; var y; } }", + output: "class C { static { var x, y; } }", + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ + messageId: "combine", + data: { type: "var" }, + type: "VariableDeclaration" + }] + }, + { + code: "class C { static { let x; foo; let y; } }", + output: null, + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ + messageId: "combine", + data: { type: "let" }, + type: "VariableDeclaration" + }] + }, + { + code: "class C { static { var x; foo; var y; } }", + output: null, + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ + messageId: "combine", + data: { type: "var" }, + type: "VariableDeclaration" + }] + }, + { + code: "class C { static { var x; if (foo) { var y; } } }", + output: null, + options: ["always"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ + messageId: "combine", + data: { type: "var" }, + type: "VariableDeclaration" + }] + }, + { + code: "class C { static { let x; let y; } }", + output: "class C { static { let x, y; } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ + messageId: "combine", + data: { type: "let" }, + type: "VariableDeclaration" + }] + }, + { + code: "class C { static { var x; var y; } }", + output: "class C { static { var x, y; } }", + options: ["consecutive"], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ + messageId: "combine", + data: { type: "var" }, + type: "VariableDeclaration" + }] + }, + { + code: "class C { static { let a = 0; let b = 1; } }", + output: "class C { static { let a = 0, b = 1; } }", + options: [{ initialized: "consecutive" }], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ + messageId: "combineInitialized", + data: { type: "let" }, + type: "VariableDeclaration" + }] + }, + { + code: "class C { static { var a = 0; var b = 1; } }", + output: "class C { static { var a = 0, b = 1; } }", + options: [{ initialized: "consecutive" }], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ + messageId: "combineInitialized", + data: { type: "var" }, + type: "VariableDeclaration" + }] } ] });