Skip to content

Commit

Permalink
Fix: prefer-const autofix multiline assignment (fixes eslint#10582)
Browse files Browse the repository at this point in the history
  • Loading branch information
sstern6 committed Oct 21, 2018
1 parent 58ff359 commit c1fdf77
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 7 deletions.
59 changes: 52 additions & 7 deletions lib/rules/prefer-const.js
Expand Up @@ -357,6 +357,9 @@ module.exports = {
const shouldMatchAnyDestructuredVariable = options.destructuring !== "all";
const ignoreReadBeforeAssign = options.ignoreReadBeforeAssign === true;
const variables = [];
let reportCount = 0;
const firstIdentifier = sourceCode.ast.tokens.find(node => node.type === "Identifier");
let name = firstIdentifier && firstIdentifier.length > 0 ? firstIdentifier.value : "";

/**
* Reports given identifier nodes if all of the nodes should be declared
Expand All @@ -377,14 +380,41 @@ module.exports = {

if (nodes.length && (shouldMatchAnyDestructuredVariable || nodesToReport.length === nodes.length)) {
const varDeclParent = findUp(nodes[0], "VariableDeclaration", parentNode => parentNode.type.endsWith("Statement"));
const shouldFix = varDeclParent &&
const isVarDecParentNull = varDeclParent === null;

if (!isVarDecParentNull && varDeclParent.declarations.length > 0) {
const firstDeclaration = varDeclParent.declarations[0];

if (firstDeclaration.init) {
const firstDecParent = firstDeclaration.init.parent;

/*
* First we check the declaration type and then depending on
* if the type is a "VariableDeclarator" or its an "ObjectPattern"
* we compare the name from the first identifier, if the names are different
* we assign the new name and reset the count of reportCount and nodeCount in
* order to check each block for the number of reported errors and base our fix
* based on comparing nodes.length and nodesToReport.length.
*/

if (firstDecParent.type === "VariableDeclarator") {

if (firstDecParent.id.name !== name) {
name = firstDecParent.id.name;
reportCount = 0;
}

if (firstDecParent.id.type === "ObjectPattern") {
if (firstDecParent.init.name !== name) {
name = firstDecParent.init.name;
reportCount = 0;
}
}
}
}
}

/*
* If there are multiple variable declarations, like {let a = 1, b = 2}, then
* do not attempt to fix if one of the declarations should be `const`. It's
* too hard to know how the developer would want to automatically resolve the issue.
*/
varDeclParent.declarations.length === 1 &&
let shouldFix = varDeclParent &&

// Don't do a fix unless the variable is initialized (or it's in a for-in or for-of loop)
(varDeclParent.parent.type === "ForInStatement" || varDeclParent.parent.type === "ForOfStatement" || varDeclParent.declarations[0].init) &&
Expand All @@ -396,6 +426,21 @@ module.exports = {
*/
nodesToReport.length === nodes.length;

if (!isVarDecParentNull && varDeclParent.declarations && varDeclParent.declarations.length !== 1) {

if (varDeclParent && varDeclParent.declarations && varDeclParent.declarations.length >= 1) {

/*
* Add nodesToReport.length to a count, then comparing the count to the length
* of the declarations in the current block.
*/

reportCount += nodesToReport.length;

shouldFix = shouldFix && (reportCount === varDeclParent.declarations.length);
}
}

nodesToReport.forEach(node => {
context.report({
node,
Expand Down
35 changes: 35 additions & 0 deletions tests/lib/rules/prefer-const.js
Expand Up @@ -454,6 +454,41 @@ ruleTester.run("prefer-const", rule, {
errors: [
{ message: "'predicate' is never reassigned. Use 'const' instead.", type: "Identifier" }
]
},
{
code: "let x = 'x', y = 'y';",
output: "const x = 'x', y = 'y';",
errors: [
{ message: "'x' is never reassigned. Use 'const' instead.", type: "Identifier" },
{ message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" }
]
},
{
code: "let x = 'x', y = 'y'; x = 1",
output: null,
errors: [
{ message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" }
]
},
{
code: "let x = 1, y = 'y'; let z = 1;",
output: "const x = 1, y = 'y'; const z = 1;",
errors: [
{ message: "'x' is never reassigned. Use 'const' instead.", type: "Identifier" },
{ message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" },
{ message: "'z' is never reassigned. Use 'const' instead.", type: "Identifier" }
]
},
{
code: "let { a, b, c} = obj; let { x, y, z} = anotherObj; x = 2;",
output: "const { a, b, c} = obj; let { x, y, z} = anotherObj; x = 2;",
errors: [
{ message: "'a' is never reassigned. Use 'const' instead.", type: "Identifier" },
{ message: "'b' is never reassigned. Use 'const' instead.", type: "Identifier" },
{ message: "'c' is never reassigned. Use 'const' instead.", type: "Identifier" },
{ message: "'y' is never reassigned. Use 'const' instead.", type: "Identifier" },
{ message: "'z' is never reassigned. Use 'const' instead.", type: "Identifier" }
]
}

]
Expand Down

0 comments on commit c1fdf77

Please sign in to comment.