From 55f1ae6de889d74a4d8c7074024726576ba5e085 Mon Sep 17 00:00:00 2001 From: golopot Date: Mon, 21 Jan 2019 01:49:52 +0800 Subject: [PATCH 1/2] Update: add fixer for `prefer-destructuring` (fixes #11151) --- lib/rules/prefer-destructuring.js | 61 +++++++++++++++++++++++-- tests/lib/rules/prefer-destructuring.js | 25 ++++++++++ 2 files changed, 81 insertions(+), 5 deletions(-) diff --git a/lib/rules/prefer-destructuring.js b/lib/rules/prefer-destructuring.js index 119fae56089..dec93d51f2d 100644 --- a/lib/rules/prefer-destructuring.js +++ b/lib/rules/prefer-destructuring.js @@ -19,6 +19,8 @@ module.exports = { url: "https://eslint.org/docs/rules/prefer-destructuring" }, + fixable: "code", + schema: [ { @@ -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)}` + ); } /** @@ -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; } @@ -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); } } } diff --git a/tests/lib/rules/prefer-destructuring.js b/tests/lib/rules/prefer-destructuring.js index a0e4aa79b87..365dc9ffdb9 100644 --- a/tests/lib/rules/prefer-destructuring.js +++ b/tests/lib/rules/prefer-destructuring.js @@ -139,6 +139,7 @@ ruleTester.run("prefer-destructuring", rule, { invalid: [ { code: "var foo = array[0];", + output: null, errors: [{ message: "Use array destructuring.", type: "VariableDeclarator" @@ -146,6 +147,7 @@ ruleTester.run("prefer-destructuring", rule, { }, { code: "foo = array[0];", + output: null, errors: [{ message: "Use array destructuring.", type: "AssignmentExpression" @@ -153,6 +155,15 @@ ruleTester.run("prefer-destructuring", rule, { }, { 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" @@ -160,6 +171,7 @@ ruleTester.run("prefer-destructuring", rule, { }, { code: "var foobar = object.bar;", + output: null, options: [{ VariableDeclarator: { object: true } }, { enforceForRenamedProperties: true }], errors: [{ message: "Use object destructuring.", @@ -168,6 +180,7 @@ ruleTester.run("prefer-destructuring", rule, { }, { code: "var foobar = object.bar;", + output: null, options: [{ object: true }, { enforceForRenamedProperties: true }], errors: [{ message: "Use object destructuring.", @@ -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.", @@ -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.", @@ -192,6 +207,7 @@ ruleTester.run("prefer-destructuring", rule, { }, { code: "var foo = object['foo'];", + output: null, errors: [{ message: "Use object destructuring.", type: "VariableDeclarator" @@ -199,6 +215,7 @@ ruleTester.run("prefer-destructuring", rule, { }, { code: "foo = object.foo;", + output: null, errors: [{ message: "Use object destructuring.", type: "AssignmentExpression" @@ -206,6 +223,7 @@ ruleTester.run("prefer-destructuring", rule, { }, { code: "foo = object['foo'];", + output: null, errors: [{ message: "Use object destructuring.", type: "AssignmentExpression" @@ -213,6 +231,7 @@ ruleTester.run("prefer-destructuring", rule, { }, { code: "var foo = array[0];", + output: null, options: [{ VariableDeclarator: { array: true } }, { enforceForRenamedProperties: true }], errors: [{ message: "Use array destructuring.", @@ -221,6 +240,7 @@ ruleTester.run("prefer-destructuring", rule, { }, { code: "foo = array[0];", + output: null, options: [{ AssignmentExpression: { array: true } }], errors: [{ message: "Use array destructuring.", @@ -229,6 +249,7 @@ ruleTester.run("prefer-destructuring", rule, { }, { code: "var foo = array[0];", + output: null, options: [ { VariableDeclarator: { array: true }, @@ -243,6 +264,7 @@ ruleTester.run("prefer-destructuring", rule, { }, { code: "var foo = array[0];", + output: null, options: [ { VariableDeclarator: { array: true }, @@ -256,6 +278,7 @@ ruleTester.run("prefer-destructuring", rule, { }, { code: "foo = array[0];", + output: null, options: [ { VariableDeclarator: { array: false }, @@ -269,6 +292,7 @@ ruleTester.run("prefer-destructuring", rule, { }, { code: "foo = object.foo;", + output: null, options: [ { VariableDeclarator: { array: true, object: false }, @@ -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" From b5648fd63954708f10c4e1b9c9c61297a31cf1a4 Mon Sep 17 00:00:00 2001 From: golopot Date: Sun, 10 Feb 2019 16:32:12 +0800 Subject: [PATCH 2/2] Chore: Add more test cases to prefer-destructuring --- tests/lib/rules/prefer-destructuring.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/lib/rules/prefer-destructuring.js b/tests/lib/rules/prefer-destructuring.js index 365dc9ffdb9..5470079ef84 100644 --- a/tests/lib/rules/prefer-destructuring.js +++ b/tests/lib/rules/prefer-destructuring.js @@ -133,7 +133,15 @@ ruleTester.run("prefer-destructuring", rule, { }, "class Foo extends Bar { static foo() {var foo = super.foo} }", "foo = bar[foo];", - "var foo = bar[foo];" + "var foo = bar[foo];", + { + code: "var {foo: {bar}} = object;", + options: [{ object: true }] + }, + { + code: "var {bar} = object.foo;", + options: [{ object: true }] + } ], invalid: [