From c4d8b0db62b859e721105d4bc0f4044ce346995e Mon Sep 17 00:00:00 2001 From: YeonJuan Date: Sun, 4 Apr 2021 08:32:03 +0900 Subject: [PATCH] Fix: no-unused-vars ignoreRestSiblings check assignments (fixes #14163) (#14264) * Fix: Check assignment reference in no-unused-vars (fixes #14163) * rename variables * add example --- docs/rules/no-unused-vars.md | 7 +++++-- lib/rules/no-unused-vars.js | 25 +++++++++++++++---------- tests/lib/rules/no-unused-vars.js | 24 ++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 12 deletions(-) diff --git a/docs/rules/no-unused-vars.md b/docs/rules/no-unused-vars.md index f730e666178..30647031eb1 100644 --- a/docs/rules/no-unused-vars.md +++ b/docs/rules/no-unused-vars.md @@ -214,8 +214,11 @@ Examples of **correct** code for the `{ "ignoreRestSiblings": true }` option: ```js /*eslint no-unused-vars: ["error", { "ignoreRestSiblings": true }]*/ -// 'type' is ignored because it has a rest property sibling. -var { type, ...coords } = data; +// 'foo' and 'bar' were ignored because they have a rest property sibling. +var { foo, ...coords } = data; + +var bar; +({ bar, ...coords } = data); ``` ### argsIgnorePattern diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js index 4dc6dc2bab3..32589099cf4 100644 --- a/lib/rules/no-unused-vars.js +++ b/lib/rules/no-unused-vars.js @@ -196,6 +196,17 @@ module.exports = { } + /** + * Checks whether a node is a sibling of the rest property or not. + * @param {ASTNode} node a node to check + * @returns {boolean} True if the node is a sibling of the rest property, otherwise false. + */ + function hasRestSibling(node) { + return node.type === "Property" && + node.parent.type === "ObjectPattern" && + REST_PROPERTY_TYPE.test(node.parent.properties[node.parent.properties.length - 1].type); + } + /** * Determines if a variable has a sibling rest property * @param {Variable} variable eslint-scope variable object. @@ -204,16 +215,10 @@ module.exports = { */ function hasRestSpreadSibling(variable) { if (config.ignoreRestSiblings) { - return variable.defs.some(def => { - const propertyNode = def.name.parent; - const patternNode = propertyNode.parent; - - return ( - propertyNode.type === "Property" && - patternNode.type === "ObjectPattern" && - REST_PROPERTY_TYPE.test(patternNode.properties[patternNode.properties.length - 1].type) - ); - }); + const hasRestSiblingDefinition = variable.defs.some(def => hasRestSibling(def.name.parent)); + const hasRestSiblingReference = variable.references.some(ref => hasRestSibling(ref.identifier.parent)); + + return hasRestSiblingDefinition || hasRestSiblingReference; } return false; diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js index 061ac08d51f..db041d46b89 100644 --- a/tests/lib/rules/no-unused-vars.js +++ b/tests/lib/rules/no-unused-vars.js @@ -291,6 +291,13 @@ ruleTester.run("no-unused-vars", rule, { parserOptions: { ecmaVersion: 2018 } }, + // https://github.com/eslint/eslint/issues/14163 + { + code: "let foo, rest;\n({ foo, ...rest } = something);\nconsole.log(rest);", + options: [{ ignoreRestSiblings: true }], + parserOptions: { ecmaVersion: 2020 } + }, + // https://github.com/eslint/eslint/issues/10952 "/*eslint use-every-a:1*/ !function(b, a) { return 1 }", @@ -588,6 +595,23 @@ ruleTester.run("no-unused-vars", rule, { } ] }, + { + code: "let type, coords;\n({ type, ...coords } = data);\n console.log(type)", + options: [{ ignoreRestSiblings: true }], + parserOptions: { ecmaVersion: 2018 }, + errors: [ + { + line: 2, + column: 13, + messageId: "unusedVar", + data: { + varName: "coords", + action: "assigned a value", + additional: "" + } + } + ] + }, // Unused rest property without ignoreRestSiblings {