Skip to content

Commit

Permalink
feat: update prefer-const for class static blocks (#15325)
Browse files Browse the repository at this point in the history
Fixes false negatives at the top level of class static blocks.

Refs #15016
  • Loading branch information
mdjermanovic committed Nov 18, 2021
1 parent b3669fd commit fd5a0b8
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 4 deletions.
19 changes: 17 additions & 2 deletions docs/rules/prefer-const.md
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -37,7 +44,6 @@ Examples of **correct** code for this rule:

```js
/*eslint prefer-const: "error"*/
/*eslint-env es6*/

// using const.
const a = 0;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion lib/rules/prefer-const.js
Expand Up @@ -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;

/**
Expand Down
131 changes: 130 additions & 1 deletion tests/lib/rules/prefer-const.js
Expand Up @@ -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: [
{
Expand Down Expand Up @@ -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" }
]
}
]
});

0 comments on commit fd5a0b8

Please sign in to comment.