Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update: add fixer for prefer-destructuring (fixes #11151) #11301

Merged
merged 2 commits into from Feb 10, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
61 changes: 56 additions & 5 deletions lib/rules/prefer-destructuring.js
Expand Up @@ -19,6 +19,8 @@ module.exports = {
url: "https://eslint.org/docs/rules/prefer-destructuring"
},

fixable: "code",

schema: [
{

Expand Down Expand Up @@ -130,10 +132,55 @@ module.exports = {
*
* @param {ASTNode} reportNode the node to report
* @param {string} type the type of destructuring that should have been done
* @param {Function|null} fix the fix function or null to pass to context.report
* @returns {void}
*/
function report(reportNode, type) {
context.report({ node: reportNode, message: "Use {{type}} destructuring.", data: { type } });
function report(reportNode, type, fix) {
context.report({
node: reportNode,
message: "Use {{type}} destructuring.",
data: { type },
fix
});
}

/**
* Determines if a node should be fixed into object destructuring
*
* The fixer only fixes the simplest case of object destructuring,
* like: `let x = a.x`;
*
* Assignment expression is not fixed.
* Array destructuring is not fixed.
* Renamed property is not fixed.
*
* @param {ASTNode} node the the node to evaluate
* @returns {boolean} whether or not the node should be fixed
*/
function shouldFix(node) {
return node.type === "VariableDeclarator" &&
node.id.type === "Identifier" &&
node.init.type === "MemberExpression" &&
node.id.name === node.init.property.name;
}

/**
* Fix a node into object destructuring.
* This function only handles the simplest case of object destructuring,
* see {@link shouldFix}.
*
* @param {SourceCodeFixer} fixer the fixer object
* @param {ASTNode} node the node to be fixed.
* @returns {Object} a fix for the node
*/
function fixIntoObjectDestructuring(fixer, node) {
const rightNode = node.init;
const sourceCode = context.getSourceCode();

return fixer.replaceText(
node,
`{${rightNode.property.name}} = ${sourceCode.getText(rightNode.object)}`
);
}

/**
Expand All @@ -155,13 +202,17 @@ module.exports = {

if (isArrayIndexAccess(rightNode)) {
if (shouldCheck(reportNode.type, "array")) {
report(reportNode, "array");
report(reportNode, "array", null);
}
return;
}

const fix = shouldFix(reportNode)
? fixer => fixIntoObjectDestructuring(fixer, reportNode)
: null;

if (shouldCheck(reportNode.type, "object") && enforceForRenamedProperties) {
report(reportNode, "object");
report(reportNode, "object", fix);
return;
}

Expand All @@ -172,7 +223,7 @@ module.exports = {
(property.type === "Literal" && leftNode.name === property.value) ||
(property.type === "Identifier" && leftNode.name === property.name && !rightNode.computed)
) {
report(reportNode, "object");
report(reportNode, "object", fix);
}
}
}
Expand Down
25 changes: 25 additions & 0 deletions tests/lib/rules/prefer-destructuring.js
Expand Up @@ -139,27 +139,39 @@ ruleTester.run("prefer-destructuring", rule, {
invalid: [
{
code: "var foo = array[0];",
output: null,
aladdin-add marked this conversation as resolved.
Show resolved Hide resolved
errors: [{
message: "Use array destructuring.",
type: "VariableDeclarator"
}]
},
{
code: "foo = array[0];",
output: null,
errors: [{
message: "Use array destructuring.",
type: "AssignmentExpression"
}]
},
{
code: "var foo = object.foo;",
output: "var {foo} = object;",
errors: [{
message: "Use object destructuring.",
type: "VariableDeclarator"
}]
},
{
code: "var foo = object.bar.foo;",
output: "var {foo} = object.bar;",
errors: [{
message: "Use object destructuring.",
type: "VariableDeclarator"
}]
},
{
code: "var foobar = object.bar;",
output: null,
options: [{ VariableDeclarator: { object: true } }, { enforceForRenamedProperties: true }],
errors: [{
message: "Use object destructuring.",
Expand All @@ -168,6 +180,7 @@ ruleTester.run("prefer-destructuring", rule, {
},
{
code: "var foobar = object.bar;",
output: null,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like this would also be safe to autofix (though this doesn't need to happen in this PR!)

options: [{ object: true }, { enforceForRenamedProperties: true }],
errors: [{
message: "Use object destructuring.",
Expand All @@ -176,6 +189,7 @@ ruleTester.run("prefer-destructuring", rule, {
},
{
code: "var foo = object[bar];",
output: null,
options: [{ VariableDeclarator: { object: true } }, { enforceForRenamedProperties: true }],
errors: [{
message: "Use object destructuring.",
Expand All @@ -184,6 +198,7 @@ ruleTester.run("prefer-destructuring", rule, {
},
{
code: "var foo = object[bar];",
output: null,
options: [{ object: true }, { enforceForRenamedProperties: true }],
errors: [{
message: "Use object destructuring.",
Expand All @@ -192,27 +207,31 @@ ruleTester.run("prefer-destructuring", rule, {
},
{
code: "var foo = object['foo'];",
output: null,
errors: [{
message: "Use object destructuring.",
type: "VariableDeclarator"
}]
},
{
code: "foo = object.foo;",
output: null,
errors: [{
message: "Use object destructuring.",
type: "AssignmentExpression"
}]
},
{
code: "foo = object['foo'];",
output: null,
errors: [{
message: "Use object destructuring.",
type: "AssignmentExpression"
}]
},
{
code: "var foo = array[0];",
output: null,
options: [{ VariableDeclarator: { array: true } }, { enforceForRenamedProperties: true }],
errors: [{
message: "Use array destructuring.",
Expand All @@ -221,6 +240,7 @@ ruleTester.run("prefer-destructuring", rule, {
},
{
code: "foo = array[0];",
output: null,
options: [{ AssignmentExpression: { array: true } }],
errors: [{
message: "Use array destructuring.",
Expand All @@ -229,6 +249,7 @@ ruleTester.run("prefer-destructuring", rule, {
},
{
code: "var foo = array[0];",
output: null,
options: [
{
VariableDeclarator: { array: true },
Expand All @@ -243,6 +264,7 @@ ruleTester.run("prefer-destructuring", rule, {
},
{
code: "var foo = array[0];",
output: null,
options: [
{
VariableDeclarator: { array: true },
Expand All @@ -256,6 +278,7 @@ ruleTester.run("prefer-destructuring", rule, {
},
{
code: "foo = array[0];",
output: null,
options: [
{
VariableDeclarator: { array: false },
Expand All @@ -269,6 +292,7 @@ ruleTester.run("prefer-destructuring", rule, {
},
{
code: "foo = object.foo;",
output: null,
options: [
{
VariableDeclarator: { array: true, object: false },
Expand All @@ -282,6 +306,7 @@ ruleTester.run("prefer-destructuring", rule, {
},
{
code: "class Foo extends Bar { static foo() {var bar = super.foo.bar} }",
output: "class Foo extends Bar { static foo() {var {bar} = super.foo} }",
errors: [{
message: "Use object destructuring.",
type: "VariableDeclarator"
Expand Down