diff --git a/docs/rules/prefer-const.md b/docs/rules/prefer-const.md index 3e5a5d0c3fe..3cdba9e4da0 100644 --- a/docs/rules/prefer-const.md +++ b/docs/rules/prefer-const.md @@ -12,7 +12,6 @@ Examples of **incorrect** code for this rule: ```js /*eslint prefer-const: "error"*/ -/*eslint-env es6*/ // it's initialized and never reassigned. let a = 3; @@ -22,6 +21,14 @@ let a; a = 0; console.log(a); +class C { + static { + let a; + a = 0; + console.log(a); + } +} + // `i` is redefined (not reassigned) on each loop step. for (let i in [1, 2, 3]) { console.log(i); @@ -37,7 +44,6 @@ Examples of **correct** code for this rule: ```js /*eslint prefer-const: "error"*/ -/*eslint-env es6*/ // using const. const a = 0; @@ -59,6 +65,15 @@ if (true) { } console.log(a); +// it's initialized in a different scope. +let a; +class C { + #x; + static { + a = obj => obj.#x; + } +} + // it's initialized at a place that we cannot write a variable declaration. let a; if (true) a = 0; diff --git a/lib/rules/prefer-const.js b/lib/rules/prefer-const.js index b44bd7592b5..38ec973fcdb 100644 --- a/lib/rules/prefer-const.js +++ b/lib/rules/prefer-const.js @@ -17,7 +17,7 @@ const astUtils = require("./utils/ast-utils"); //------------------------------------------------------------------------------ const PATTERN_TYPE = /^(?:.+?Pattern|RestElement|SpreadProperty|ExperimentalRestProperty|Property)$/u; -const DECLARATION_HOST_TYPE = /^(?:Program|BlockStatement|SwitchCase)$/u; +const DECLARATION_HOST_TYPE = /^(?:Program|BlockStatement|StaticBlock|SwitchCase)$/u; const DESTRUCTURING_HOST_TYPE = /^(?:VariableDeclarator|AssignmentExpression)$/u; /** diff --git a/tests/lib/rules/prefer-const.js b/tests/lib/rules/prefer-const.js index c591d236583..0a44b0bd017 100644 --- a/tests/lib/rules/prefer-const.js +++ b/tests/lib/rules/prefer-const.js @@ -173,7 +173,56 @@ ruleTester.run("prefer-const", rule, { // https://github.com/eslint/eslint/issues/10520 "const x = [1,2]; let y; [,y] = x; y = 0;", - "const x = [1,2,3]; let y, z; [y,,z] = x; y = 0; z = 0;" + "const x = [1,2,3]; let y, z; [y,,z] = x; y = 0; z = 0;", + + { + code: "class C { static { let a = 1; a = 2; } }", + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let a; a = 1; a = 2; } }", + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "let a; class C { static { a = 1; } }", + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let a; if (foo) { a = 1; } } }", + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let a; if (foo) a = 1; } }", + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { let a, b; if (foo) { ({ a, b } = foo); } } }", + output: null, + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "useConst", data: { name: "a" }, type: "Identifier" }, + { messageId: "useConst", data: { name: "b" }, type: "Identifier" } + ] + }, + { + code: "class C { static { let a, b; if (foo) ({ a, b } = foo); } }", + output: null, + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "useConst", data: { name: "a" }, type: "Identifier" }, + { messageId: "useConst", data: { name: "b" }, type: "Identifier" } + ] + }, + { + code: "class C { static { a; } } let a = 1; ", + options: [{ ignoreReadBeforeAssign: true }], + parserOptions: { ecmaVersion: 2022 } + }, + { + code: "class C { static { () => a; let a = 1; } };", + options: [{ ignoreReadBeforeAssign: true }], + parserOptions: { ecmaVersion: 2022 } + } ], invalid: [ { @@ -555,6 +604,86 @@ ruleTester.run("prefer-const", rule, { code: "/*eslint no-undef-init:error*/ let foo = undefined;", output: "/*eslint no-undef-init:error*/ const foo = undefined;", errors: 2 + }, + + { + code: "let a = 1; class C { static { a; } }", + output: "const a = 1; class C { static { a; } }", + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "useConst", data: { name: "a" }, type: "Identifier" }] + }, + { + + // this is a TDZ error with either `let` or `const`, but that isn't a concern of this rule + code: "class C { static { a; } } let a = 1;", + output: "class C { static { a; } } const a = 1;", + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "useConst", data: { name: "a" }, type: "Identifier" }] + }, + { + code: "class C { static { let a = 1; } }", + output: "class C { static { const a = 1; } }", + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "useConst", data: { name: "a" }, type: "Identifier" }] + }, + { + code: "class C { static { if (foo) { let a = 1; } } }", + output: "class C { static { if (foo) { const a = 1; } } }", + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "useConst", data: { name: "a" }, type: "Identifier" }] + }, + { + code: "class C { static { let a = 1; if (foo) { a; } } }", + output: "class C { static { const a = 1; if (foo) { a; } } }", + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "useConst", data: { name: "a" }, type: "Identifier" }] + }, + { + code: "class C { static { if (foo) { let a; a = 1; } } }", + output: null, + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "useConst", data: { name: "a" }, type: "Identifier" }] + }, + { + code: "class C { static { let a; a = 1; } }", + output: null, + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "useConst", data: { name: "a" }, type: "Identifier", column: 27 }] + }, + { + code: "class C { static { let { a, b } = foo; } }", + output: "class C { static { const { a, b } = foo; } }", + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "useConst", data: { name: "a" }, type: "Identifier" }, + { messageId: "useConst", data: { name: "b" }, type: "Identifier" } + ] + }, + { + code: "class C { static { let a, b; ({ a, b } = foo); } }", + output: null, + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "useConst", data: { name: "a" }, type: "Identifier" }, + { messageId: "useConst", data: { name: "b" }, type: "Identifier" } + ] + }, + { + code: "class C { static { let a; let b; ({ a, b } = foo); } }", + output: null, + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "useConst", data: { name: "a" }, type: "Identifier" }, + { messageId: "useConst", data: { name: "b" }, type: "Identifier" } + ] + }, + { + code: "class C { static { let a; a = 0; console.log(a); } }", + output: null, + parserOptions: { ecmaVersion: 2022 }, + errors: [ + { messageId: "useConst", data: { name: "a" }, type: "Identifier" } + ] } ] });