diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js index d17253acf74..ac9f0c9bedc 100644 --- a/lib/rules/no-unused-vars.js +++ b/lib/rules/no-unused-vars.js @@ -50,6 +50,8 @@ module.exports = { url: "https://eslint.org/docs/latest/rules/no-unused-vars" }, + hasSuggestions: true, + schema: [ { oneOf: [ @@ -98,7 +100,8 @@ module.exports = { messages: { unusedVar: "'{{varName}}' is {{action}} but never used{{additional}}.", - usedIgnoredVar: "'{{varName}}' is marked as ignored but is used{{additional}}." + usedIgnoredVar: "'{{varName}}' is marked as ignored but is used{{additional}}.", + removeVar: "Remove unused variable '{{varName}}'." } }, @@ -858,10 +861,539 @@ module.exports = { messageId: "unusedVar", data: unusedVar.references.some(ref => ref.isWrite()) ? getAssignedMessageData(unusedVar) - : getDefinedMessageData(unusedVar) + : getDefinedMessageData(unusedVar), + suggest: [ + { + messageId: "removeVar", + data: { + varName: unusedVar.name + }, + fix(fixer) { + const id = unusedVar.identifiers[0]; + const parent = id.parent; + const parentType = parent.type; + const tokenBefore = sourceCode.getTokenBefore(id); + const tokenAfter = sourceCode.getTokenAfter(id); + const isFunction = astUtils.isFunction; + const isLoop = astUtils.isLoop; + + /** + * get range from token before of a given node + * @param {ASTNode} node node of identifier + * @param {number} skips number of token to skip + * @returns {number} start range of token before the identifier + */ + function getPreviousTokenStart(node, skips) { + return sourceCode.getTokenBefore(node, skips).range[0]; + } + + /** + * get range to token after of a given node + * @param {ASTNode} node node of identifier + * @param {number} skips number of token to skip + * @returns {number} end range of token after the identifier + */ + function getNextTokenEnd(node, skips) { + return sourceCode.getTokenAfter(node, skips).range[1]; + } + + /** + * get the value of token before of a given node + * @param {ASTNode} node node of identifier + * @returns {string} value of token before the identifier + */ + function getTokenBeforeValue(node) { + return sourceCode.getTokenBefore(node).value; + } + + /** + * get the value of token after of a given node + * @param {ASTNode} node node of identifier + * @returns {string} value of token after the identifier + */ + function getTokenAfterValue(node) { + return sourceCode.getTokenAfter(node).value; + } + + /** + * Check if an array has a single element with null as other element. + * @param {ASTNode} node ArrayPattern node + * @returns {boolean} true if array has single element with other null elements + */ + function hasSingleElement(node) { + return node.elements.filter(e => e !== null).length === 1; + } + + /** + * give fixes for unused variables in function parameters + * @param {ASTNode} node node to check + * @returns {Object} fixer object + */ + function fixFunctionParameters(node) { + const parentNode = node.parent; + + if (isFunction(parentNode)) { + + // remove unused function parameter if there is only a single parameter + if (parentNode.params.length === 1) { + return fixer.removeRange(node.range); + } + + // remove first unused function parameter when there are multiple parameters + if (getTokenBeforeValue(node) === "(" && getTokenAfterValue(node) === ",") { + return fixer.removeRange([node.range[0], getNextTokenEnd(node)]); + } + + // remove unused function parameters except first one when there are multiple parameters + return fixer.removeRange([getPreviousTokenStart(node), node.range[1]]); + } + + return null; + } + + /** + * Gets fixes in variable declarations and function parameters + * @param {ASTNode} node parent node of identifier + * @returns {Object} fixer object + */ + function fixVariables(node) { + const parentNode = node.parent; + + // remove unused declared variables such as var a = b; or var a = b, c; + if (parentNode.type === "VariableDeclarator") { + + // remove unused declared variable with single declaration such as 'var a = b;' + if (parentNode.parent.declarations.length === 1) { + return fixer.removeRange(parentNode.parent.range); + } + + // remove unused declared variable with multiple declaration except first one such as 'var a = b, c = d;' + if (getTokenBeforeValue(parentNode) === ",") { + return fixer.removeRange([getPreviousTokenStart(parentNode), parentNode.range[1]]); + } + + // remove first unused declared variable when there are multiple declarations + return fixer.removeRange([parentNode.range[0], getNextTokenEnd(parentNode)]); + } + + return fixFunctionParameters(node); + } + + /** + * fix unused variables inside object and array pattern + * @param {ASTNode} node parent node to check + * @returns {Object} fixer object + */ + function fixObjectAndArrayVariableVariable(node) { + const parentNode = node.parent; + + if (parentNode.type === "VariableDeclarator") { + + // skip variable in for (const [ foo ] of bar); + if (isLoop(parentNode.parent.parent)) { + return null; + } + + // remove complete declaration when there is an unused variable in 'const { a } = foo;', same for arrays. + if (parentNode.parent.declarations.length === 1) { + return fixer.removeRange(parentNode.parent.range); + } + + // fix 'let bar = "hello", { a } = foo;' to 'let bar = "hello";' if 'a' is unused, same for arrays. + if (getTokenBeforeValue(parentNode) === ",") { + return fixer.removeRange([getPreviousTokenStart(parentNode), parentNode.range[1]]); + } + + // fix 'let { a } = foo, bar = "hello";' to 'let bar = "hello";' if 'a' is unused, same for arrays. + return fixer.removeRange([parentNode.range[0], getNextTokenEnd(parentNode)]); + } + + // fixes [{a: {k}}], [{a: [k]}] + if (getTokenBeforeValue(node) === ":") { + if (parentNode.parent.type === "ObjectPattern") { + // eslint-disable-next-line no-use-before-define -- due to interdependency of functions + return fixObjectWithValueSeperator(node); + } + } + + return fixFunctionParameters(node); + } + + /** + * fix nested object like { a: { b } } + * @param {ASTNode} node parent node to check + * @returns {Object} fixer object + */ + function fixNestedObjectVariable(node) { + const parentNode = node.parent; + + // fix for {{ a: { b } }} + if ( + parentNode.parent.parent.parent.type === "ObjectPattern" && + parentNode.parent.properties.length === 1 + ) { + return fixNestedObjectVariable(parentNode.parent); + } + + // fix for { a: { b } } + if (parentNode.parent.type === "ObjectPattern") { + + // fix for unused variables in dectructured object with single property in variable decalartion and function parameter + if (parentNode.parent.properties.length === 1) { + return fixVariables(parentNode.parent); + } + + // fix for first unused property when there are multiple properties such as '{ a: { b }, c }' + if (getTokenBeforeValue(parentNode) === "{") { + return fixer.removeRange( + [parentNode.range[0], getNextTokenEnd(parentNode)] + ); + } + + // fix for unused property except first one when there are multiple properties such as '{ k, a: { b } }' + return fixer.removeRange([getPreviousTokenStart(parentNode), parentNode.range[1]]); + } + + return null; + } + + /** + * fix unused variables in array and nested array + * @param {ASTNode} node parent node to check + * @returns {Object} fixer object + */ + function fixNestedArrayVariable(node) { + const parentNode = node.parent; + + // fix for nested arrays [[ a ]] + if (parentNode.parent.type === "ArrayPattern" && hasSingleElement(parentNode)) { + return fixNestedArrayVariable(parentNode); + } + + if (hasSingleElement(parentNode)) { + + // fixes { a: [{ b }] } or { a: [[ b ]] } + if (getTokenBeforeValue(parentNode) === ":") { + return fixObjectAndArrayVariableVariable(parentNode); + } + + // fixes [a, ...[[ b ]]] or [a, ...[{ b }]] + if (parentNode.parent.type === "RestElement") { + // eslint-disable-next-line no-use-before-define -- due to interdependency of functions + return fixRestInPattern(parentNode.parent); + } + + // fix unused variables in destructured array in variable declaration or function parameter + return fixVariables(parentNode); + } + + // remove last unused array element + if ( + getTokenBeforeValue(node) === "," && + getTokenAfterValue(node) === "]" + ) { + return fixer.removeRange([getPreviousTokenStart(node), node.range[1]]); + } + + // remove unused array element + return fixer.removeRange(node.range); + } + + /** + * fix cases like {a: {k}} or {a: [k]} + * @param {ASTNode} node parent node to check + * @returns {Object} fixer object + */ + function fixObjectWithValueSeperator(node) { + const parentNode = node.parent.parent; + + // fix cases like [{a : { b }}] or [{a : [ b ]}] + if ( + parentNode.parent.type === "ArrayPattern" && + parentNode.properties.length === 1 + ) { + return fixNestedArrayVariable(parentNode); + } + + // fix cases like {a: {k}} or {a: [k]} + return fixNestedObjectVariable(node); + } + + /** + * fix [...[a]] or [...{a}] like patterns + * @param {ASTNode} node parent node to check + * @returns {Object} fixer object + */ + function fixRestInPattern(node) { + const parentNode = node.parent; + + // fix [...[a]] or [...{a}] in function parameters + if (isFunction(parentNode)) { + if (parentNode.params.length === 1) { + return fixer.removeRange(node.range); + } + + return fixer.removeRange([getPreviousTokenStart(node), node.range[1]]); + } + + // fix rest in nested array pattern like [[a, ...[b]]] + if (parentNode.type === "ArrayPattern") { + + // fix [[...[b]]] + if (hasSingleElement(parentNode)) { + if (parentNode.parent.type === "ArrayPattern") { + return fixNestedArrayVariable(parentNode); + } + + // fix 'const [...[b]] = foo; and function foo([...[b]]) {} + return fixVariables(parentNode); + } + + // fix [[a, ...[b]]] + return fixer.removeRange([getPreviousTokenStart(node), node.range[1]]); + } + + return null; + } + + // skip fix when variable is reassigned + if (writeReferences.length > 1 && parentType !== "AssignmentPattern") { + return null; + } + + // remove declared variables such as var a; or var a, b; + if (parentType === "VariableDeclarator") { + if (parent.parent.declarations.length === 1) { + + // prevent fix of variable in forOf and forIn loops. + if (isLoop(parent.parent.parent)) { + return null; + } + + // // remove unused declared variable with single declaration like 'var a = b;' + return fixer.removeRange(parent.parent.range); + } + + // // remove unused declared variable with multiple declaration except first one like 'var a = b, c = d;' + if (tokenBefore.value === ",") { + return fixer.removeRange([tokenBefore.range[0], parent.range[1]]); + } + + // remove first unused declared variable when there are multiple declarations + return fixer.removeRange([parent.range[0], getNextTokenEnd(parent)]); + } + + // remove variables in object patterns + if (parent.parent.type === "ObjectPattern") { + if (parent.parent.properties.length === 1) { + + // fix [a, ...{b}] + if (parent.parent.parent.type === "RestElement") { + return fixRestInPattern(parent.parent.parent); + } + + // fix [{ a }] + if (parent.parent.parent.type === "ArrayPattern") { + return fixNestedArrayVariable(parent.parent); + } + + /* + * var {a} = foo; + * function a({a}) {} + * fix const { a: { b } } = foo; + */ + return fixObjectAndArrayVariableVariable(parent.parent); + } + + // fix const { a:b } = foo; + if (tokenBefore.value === ":") { + + // remove first unused variable in const { a:b } = foo; + if (getTokenBeforeValue(parent) === "{" && getTokenAfterValue(parent) === ",") { + return fixer.removeRange([parent.range[0], getNextTokenEnd(parent)]); + } + + // remove unused variables in const { a: b, c: d } = foo; except first one + return fixer.removeRange([getPreviousTokenStart(parent), id.range[1]]); + } + } + + // remove unused varibales inside an array + if (parentType === "ArrayPattern") { + if (hasSingleElement(parent)) { + + // fix [a, ...[b]] + if (parent.parent.type === "RestElement") { + return fixRestInPattern(parent.parent); + } + + // fix [ [a] ] + if (parent.parent.type === "ArrayPattern") { + return fixNestedArrayVariable(parent); + } + + /* + * fix var foo = [a]; + * fix function foo([a]) {} + * fix const { a: [b] } = foo; + */ + return fixObjectAndArrayVariableVariable(parent); + } + + // if "a" is unused in [a, b ,c] fixes to [, b c] + if (tokenBefore.value === "," && tokenAfter.value === ",") { + return fixer.removeRange(id.range); + } + } + + // remove unused rest elements + if (parentType === "RestElement") { + + // fix [a, ...rest] + if (parent.parent.type === "ArrayPattern") { + if (hasSingleElement(parent.parent)) { + + // fix [[...rest]] when there is only rest element + if ( + parent.parent.parent.type === "ArrayPattern" + ) { + return fixNestedArrayVariable(parent.parent); + } + + // fix 'const [...rest] = foo;' and 'function foo([...rest]) {}' + return fixVariables(parent.parent); + } + + // fix [a, ...rest] + return fixer.removeRange([getPreviousTokenStart(id, 1), id.range[1]]); + } + + // fix { a, ...rest} + if (parent.parent.type === "ObjectPattern") { + + // fix 'const {...rest} = foo;' and 'function foo({...rest}) {}' + if (parent.parent.properties.length === 1) { + return fixVariables(parent.parent); + } + + // fix { a, ...rest} when there are multiple properties + return fixer.removeRange([getPreviousTokenStart(id, 1), id.range[1]]); + } + + // fix function foo(...rest) {} + if (isFunction(parent.parent)) { + + // remove unused rest in function parameter if there is only single parameter + if (parent.parent.params.length === 1) { + return fixer.removeRange(parent.range); + } + + // remove unused rest in function parameter if there multiple parameter + return fixer.removeRange([getPreviousTokenStart(parent), parent.range[1]]); + } + } + + if (parentType === "AssignmentPattern") { + + // fix [a = aDefault] + if (parent.parent.type === "ArrayPattern") { + return fixNestedArrayVariable(parent); + } + + // fix {a = aDefault} + if (parent.parent.parent.type === "ObjectPattern") { + if (parent.parent.parent.properties.length === 1) { + + // fixes [{a = aDefault}] + if (parent.parent.parent.parent.type === "ArrayPattern") { + return fixNestedArrayVariable(parent.parent.parent); + } + + // fix 'const {a = aDefault} = foo;' and 'function foo({a = aDefault}) {}' + return fixVariables(parent.parent.parent); + } + + // fix unused 'a' in {a = aDefault} if it is the first property + if ( + getTokenBeforeValue(parent.parent) === "{" && + getTokenAfterValue(parent.parent) === "," + ) { + return fixer.removeRange([parent.parent.range[0], getNextTokenEnd(parent.parent)]); + } + + // fix unused 'b' in {a, b = aDefault} if it is not the first property + return fixer.removeRange([getPreviousTokenStart(parent.parent), parent.parent.range[1]]); + } + } + + // remove unused functions + if (parentType === "FunctionDeclaration" && parent.id === id) { + return fixer.removeRange(parent.range); + } + + // remove unused default import + if (parentType === "ImportDefaultSpecifier") { + + // remove unused default import when there are not other imports + if (!parent.parent.specifiers.some(e => e.type === "ImportSpecifier")) { + return fixer.removeRange(parent.parent.range); + } + + // remove unused default import when there are other imports also + return fixer.removeRange([id.range[0], tokenAfter.range[1]]); + } + + // remove unused imports when there is a single import + if ( + parentType === "ImportSpecifier" && + parent.parent.specifiers.sort(e => e.type === "ImportSpecifier").length === 1 + ) { + + // remove unused import when there is no default import + if (!parent.parent.specifiers.some(e => e.type === "ImportDefaultSpecifier")) { + return fixer.removeRange(parent.parent.range); + } + + // remove unused import when there is a default import + return fixer.removeRange([getPreviousTokenStart(id, 1), tokenAfter.range[1]]); + } + + // skip error in catch(error) variable + if (parentType === "CatchClause") { + return null; + } + + // remove unused declared classes + if (parentType === "ClassDeclaration") { + return fixer.removeRange(parent.range); + } + + // remove unused varible that is in a sequence [a,b] fixes to [a] + if (tokenBefore.value === ",") { + return fixer.removeRange([tokenBefore.range[0], id.range[1]]); + } + + // remove unused varible that is in a sequence inside function arguments and object pattern + if (tokenAfter.value === ",") { + + // fix function foo(a, b) {} + if (tokenBefore.value === "(") { + return fixer.removeRange([id.range[0], tokenAfter.range[1]]); + } + + // fix const {a, b} = foo; + if (tokenBefore.value === "{") { + return fixer.removeRange([id.range[0], tokenAfter.range[1]]); + } + } + + return fixer.removeRange(id.range); + } + } + ] }); - // If there are no regular declaration, report the first `/*globals*/` comment directive. + // If there are no regular declaration, report the first `/*globals*/` comment directive. } else if (unusedVar.eslintExplicitGlobalComments) { const directiveComment = unusedVar.eslintExplicitGlobalComments[0]; diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js index 6e98b93f3a1..14e2072f1e1 100644 --- a/tests/lib/linter/linter.js +++ b/tests/lib/linter/linter.js @@ -6357,7 +6357,23 @@ var a = "test2"; messageId: "unusedVar", nodeType: "Identifier", ruleId: "no-unused-vars", - severity: 2 + severity: 2, + suggestions: [ + { + data: { + varName: "bbb" + }, + desc: "Remove unused variable 'bbb'.", + fix: { + range: [ + 99, + 111 + ], + text: "" + }, + messageId: "removeVar" + } + ] }] ); @@ -12927,7 +12943,23 @@ var a = "test2"; messageId: "unusedVar", nodeType: "Identifier", ruleId: "no-unused-vars", - severity: 2 + severity: 2, + suggestions: [ + { + data: { + varName: "bbb" + }, + desc: "Remove unused variable 'bbb'.", + fix: { + range: [ + 99, + 111 + ], + text: "" + }, + messageId: "removeVar" + } + ] }] ); diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js index 2f2d4f2125c..9915c3e22af 100644 --- a/tests/lib/rules/no-unused-vars.js +++ b/tests/lib/rules/no-unused-vars.js @@ -53,11 +53,12 @@ const ruleTester = new RuleTester({ /** * Returns an expected error for defined-but-not-used variables. * @param {string} varName The name of the variable + * @param {Array} suggestions The suggestions for the unused variable * @param {string} [additional] The additional text for the message data * @param {string} [type] The node type (defaults to "Identifier") * @returns {Object} An expected error object */ -function definedError(varName, additional = "", type = "Identifier") { +function definedError(varName, suggestions = [], additional = "", type = "Identifier") { return { messageId: "unusedVar", data: { @@ -65,18 +66,20 @@ function definedError(varName, additional = "", type = "Identifier") { action: "defined", additional }, - type + type, + suggestions }; } /** * Returns an expected error for assigned-but-not-used variables. * @param {string} varName The name of the variable + * @param {Array} suggestions The suggestions for the unused variable * @param {string} [additional] The additional text for the message data * @param {string} [type] The node type (defaults to "Identifier") * @returns {Object} An expected error object */ -function assignedError(varName, additional = "", type = "Identifier") { +function assignedError(varName, suggestions = [], additional = "", type = "Identifier") { return { messageId: "unusedVar", data: { @@ -84,7 +87,8 @@ function assignedError(varName, additional = "", type = "Identifier") { action: "assigned a value", additional }, - type + type, + suggestions }; } @@ -499,50 +503,103 @@ ruleTester.run("no-unused-vars", rule, { } ], invalid: [ - { code: "function foox() { return foox(); }", errors: [definedError("foox")] }, - { code: "(function() { function foox() { if (true) { return foox(); } } }())", errors: [definedError("foox")] }, - { code: "var a=10", errors: [assignedError("a")] }, - { code: "function f() { var a = 1; return function(){ f(a *= 2); }; }", errors: [definedError("f")] }, - { code: "function f() { var a = 1; return function(){ f(++a); }; }", errors: [definedError("f")] }, - { code: "/*global a */", errors: [definedError("a", "", "Program")] }, - { code: "function foo(first, second) {\ndoStuff(function() {\nconsole.log(second);});};", errors: [definedError("foo")] }, - { code: "var a=10;", options: ["all"], errors: [assignedError("a")] }, + { code: "function foox() { return foox(); }", errors: [definedError("foox", [{ output: "", messageId: "removeVar", data: { varName: "foox" } }])] }, + { code: "(function() { function foox() { if (true) { return foox(); } } }())", errors: [definedError("foox", [{ output: "(function() { }())", messageId: "removeVar", data: { varName: "foox" } }])] }, + { code: "var a=10", errors: [assignedError("a", [{ output: "", messageId: "removeVar", data: { varName: "a" } }])] }, + { code: "function f() { var a = 1; return function(){ f(a *= 2); }; }", errors: [definedError("f", [{ output: "", messageId: "removeVar", data: { varName: "f" } }])] }, + { code: "function f() { var a = 1; return function(){ f(++a); }; }", errors: [definedError("f", [{ output: "", messageId: "removeVar", data: { varName: "f" } }])] }, + { code: "/*global a */", errors: [definedError("a", [], "", "Program")] }, + { code: "function foo(first, second) {\ndoStuff(function() {\nconsole.log(second);});}", errors: [definedError("foo", [{ output: "", messageId: "removeVar", data: { varName: "foo" } }])] }, + { code: "var a=10;", options: ["all"], errors: [assignedError("a", [{ output: "", messageId: "removeVar", data: { varName: "a" } }])] }, { code: "var a=10; a=20;", options: ["all"], errors: [assignedError("a")] }, - { code: "var a=10; (function() { var a = 1; alert(a); })();", options: ["all"], errors: [assignedError("a")] }, - { code: "var a=10, b=0, c=null; alert(a+b)", options: ["all"], errors: [assignedError("c")] }, - { code: "var a=10, b=0, c=null; setTimeout(function() { var b=2; alert(a+b+c); }, 0);", options: ["all"], errors: [assignedError("b")] }, - { code: "var a=10, b=0, c=null; setTimeout(function() { var b=2; var c=2; alert(a+b+c); }, 0);", options: ["all"], errors: [assignedError("b"), assignedError("c")] }, - { code: "function f(){var a=[];return a.map(function(){});}", options: ["all"], errors: [definedError("f")] }, - { code: "function f(){var a=[];return a.map(function g(){});}", options: ["all"], errors: [definedError("f")] }, + { code: "var a=10; (function() { var a = 1; alert(a); })();", options: ["all"], errors: [assignedError("a", [{ output: " (function() { var a = 1; alert(a); })();", messageId: "removeVar", data: { varName: "a" } }])] }, + { code: "var a=10, b=0, c=null; alert(a+b)", options: ["all"], errors: [assignedError("c", [{ output: "var a=10, b=0; alert(a+b)", messageId: "removeVar", data: { varName: "c" } }])] }, + { code: "var a=10, b=0, c=null; setTimeout(function() { var b=2; alert(a+b+c); }, 0);", options: ["all"], errors: [assignedError("b", [{ output: "var a=10, c=null; setTimeout(function() { var b=2; alert(a+b+c); }, 0);", messageId: "removeVar", data: { varName: "b" } }])] }, + { + code: "var a=10, b=0, c=null; setTimeout(function() { var b=2; var c=2; alert(a+b+c); }, 0);", + options: ["all"], + errors: [ + assignedError("b", [{ output: "var a=10, c=null; setTimeout(function() { var b=2; var c=2; alert(a+b+c); }, 0);", messageId: "removeVar", data: { varName: "b" } }]), + assignedError("c", [{ output: "var a=10, b=0; setTimeout(function() { var b=2; var c=2; alert(a+b+c); }, 0);", messageId: "removeVar", data: { varName: "c" } }]) + ] + }, + { code: "function f(){var a=[];return a.map(function(){});}", options: ["all"], errors: [definedError("f", [{ output: "", messageId: "removeVar", data: { varName: "f" } }])] }, + { code: "function f(){var a=[];return a.map(function g(){});}", options: ["all"], errors: [definedError("f", [{ output: "", messageId: "removeVar", data: { varName: "f" } }])] }, { code: "function foo() {function foo(x) {\nreturn x; }; return function() {return foo; }; }", errors: [{ messageId: "unusedVar", data: { varName: "foo", action: "defined", additional: "" }, line: 1, - type: "Identifier" + type: "Identifier", + suggestions: [ + { + output: "", + messageId: "removeVar", + data: { varName: "foo" } + } + ] }] }, - { code: "function f(){var x;function a(){x=42;}function b(){alert(x);}}", options: ["all"], errors: 3 }, - { code: "function f(a) {}; f();", options: ["all"], errors: [definedError("a")] }, - { code: "function a(x, y, z){ return y; }; a();", options: ["all"], errors: [definedError("z")] }, - { code: "var min = Math.min", options: ["all"], errors: [assignedError("min")] }, - { code: "var min = {min: 1}", options: ["all"], errors: [assignedError("min")] }, - { code: "Foo.bar = function(baz) { return 1; };", options: ["all"], errors: [definedError("baz")] }, - { code: "var min = {min: 1}", options: [{ vars: "all" }], errors: [assignedError("min")] }, - { code: "function gg(baz, bar) { return baz; }; gg();", options: [{ vars: "all" }], errors: [definedError("bar")] }, - { code: "(function(foo, baz, bar) { return baz; })();", options: [{ vars: "all", args: "after-used" }], errors: [definedError("bar")] }, - { code: "(function(foo, baz, bar) { return baz; })();", options: [{ vars: "all", args: "all" }], errors: [definedError("foo"), definedError("bar")] }, - { code: "(function z(foo) { var bar = 33; })();", options: [{ vars: "all", args: "all" }], errors: [definedError("foo"), assignedError("bar")] }, - { code: "(function z(foo) { z(); })();", options: [{}], errors: [definedError("foo")] }, - { code: "function f() { var a = 1; return function(){ f(a = 2); }; }", options: [{}], errors: [definedError("f"), assignedError("a")] }, - { code: "import x from \"y\";", languageOptions: { ecmaVersion: 6, sourceType: "module" }, errors: [definedError("x")] }, - { code: "export function fn2({ x, y }) {\n console.log(x); \n};", languageOptions: { ecmaVersion: 6, sourceType: "module" }, errors: [definedError("y")] }, - { code: "export function fn2( x, y ) {\n console.log(x); \n};", languageOptions: { ecmaVersion: 6, sourceType: "module" }, errors: [definedError("y")] }, + { + code: "function f(){var x;function a(){x=42;}function b(){alert(x);}}", + options: ["all"], + errors: [ + definedError("f", [{ output: "", messageId: "removeVar", data: { varName: "f" } }]), + definedError("a", [{ output: "function f(){var x;function b(){alert(x);}}", messageId: "removeVar", data: { varName: "a" } }]), + definedError("b", [{ output: "function f(){var x;function a(){x=42;}}", messageId: "removeVar", data: { varName: "b" } }]) + ] + }, + { code: "function f(a) {}; f();", options: ["all"], errors: [definedError("a", [{ output: "function f() {}; f();", messageId: "removeVar", data: { varName: "a" } }])] }, + { code: "function a(x, y, z){ return y; }; a();", options: ["all"], errors: [definedError("z", [{ output: "function a(x, y){ return y; }; a();", messageId: "removeVar", data: { varName: "z" } }])] }, + { code: "var min = Math.min", options: ["all"], errors: [assignedError("min", [{ output: "", messageId: "removeVar", data: { varName: "min" } }])] }, + { code: "var min = {min: 1}", options: ["all"], errors: [assignedError("min", [{ output: "", messageId: "removeVar", data: { varName: "min" } }])] }, + { code: "Foo.bar = function(baz) { return 1; }", options: ["all"], errors: [definedError("baz", [{ output: "Foo.bar = function() { return 1; }", messageId: "removeVar", data: { varName: "baz" } }])] }, + { code: "var min = {min: 1}", options: [{ vars: "all" }], errors: [assignedError("min", [{ output: "", messageId: "removeVar", data: { varName: "min" } }])] }, + { code: "function gg(baz, bar) { return baz; }; gg();", options: [{ vars: "all" }], errors: [definedError("bar", [{ output: "function gg(baz) { return baz; }; gg();", messageId: "removeVar", data: { varName: "bar" } }])] }, + { + code: "(function(foo, baz, bar) { return baz; })();", + options: [{ vars: "all", args: "after-used" }], + errors: [definedError("bar", [{ output: "(function(foo, baz) { return baz; })();", messageId: "removeVar", data: { varName: "bar" } }])] + }, + { + code: "(function(foo, baz, bar) { return baz; })();", + options: [{ vars: "all", args: "all" }], + errors: [ + definedError("foo", [{ output: "(function( baz, bar) { return baz; })();", messageId: "removeVar", data: { varName: "foo" } }]), + definedError("bar", [{ output: "(function(foo, baz) { return baz; })();", messageId: "removeVar", data: { varName: "bar" } }]) + ] + }, + { + code: "(function z(foo) { var bar = 33; })();", + options: [{ vars: "all", args: "all" }], + errors: [ + definedError("foo", [{ output: "(function z() { var bar = 33; })();", messageId: "removeVar", data: { varName: "foo" } }]), + assignedError("bar", [{ output: "(function z(foo) { })();", messageId: "removeVar", data: { varName: "bar" } }]) + ] + }, + { + code: "(function z(foo) { z(); })();", + options: [{}], + errors: [ + definedError("foo", [{ output: "(function z() { z(); })();", messageId: "removeVar", data: { varName: "foo" } }]) + ] + }, + { + code: "function f() { var a = 1; return function(){ f(a = 2); }; }", + options: [{}], + errors: [ + definedError("f", [{ output: "", messageId: "removeVar", data: { varName: "f" } }]), + assignedError("a", [{ output: "function f() { return function(){ f(a = 2); }; }", messageId: "removeVar", data: { varName: "a" } }]) + ] + }, + { code: "import x from \"y\";", languageOptions: { ecmaVersion: 6, sourceType: "module" }, errors: [definedError("x", [{ output: "", messageId: "removeVar", data: { varName: "x" } }])] }, + { code: "export function fn2({ x, y }) {\n console.log(x); \n};", languageOptions: { ecmaVersion: 6, sourceType: "module" }, errors: [definedError("y", [{ output: "export function fn2({ x }) {\n console.log(x); \n};", messageId: "removeVar", data: { varName: "y" } }])] }, + { code: "export function fn2( x, y ) {\n console.log(x); \n};", languageOptions: { ecmaVersion: 6, sourceType: "module" }, errors: [definedError("y", [{ output: "export function fn2( x ) {\n console.log(x); \n};", messageId: "removeVar", data: { varName: "y" } }])] }, // exported - { code: "/*exported max*/ var max = 1, min = {min: 1}", errors: [assignedError("min")] }, - { code: "/*exported x*/ var { x, y } = z", languageOptions: { ecmaVersion: 6 }, errors: [assignedError("y")] }, + { code: "/*exported max*/ var max = 1, min = {min: 1}", errors: [assignedError("min", [{ output: "/*exported max*/ var max = 1", messageId: "removeVar", data: { varName: "min" } }])] }, + { code: "/*exported x*/ var { x, y } = z", languageOptions: { ecmaVersion: 6 }, errors: [assignedError("y", [{ output: "/*exported x*/ var { x } = z", messageId: "removeVar", data: { varName: "y" } }])] }, // ignore pattern { @@ -556,7 +613,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "b", action: "defined", additional: ". Allowed unused vars must match /^_/u" - } + }, + suggestions: [ + { + output: "var _a; ", + messageId: "removeVar", + data: { varName: "b" } + } + ] }] }, { @@ -570,7 +634,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "c_", action: "defined", additional: ". Allowed unused vars must match /^_/u" - } + }, + suggestions: [ + { + output: "var a; function foo() { var _b; } foo();", + messageId: "removeVar", + data: { varName: "c_" } + } + ] }] }, { @@ -584,7 +655,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "a", action: "defined", additional: ". Allowed unused args must match /^_/u" - } + }, + suggestions: [ + { + output: "function foo( _b) { } foo();", + messageId: "removeVar", + data: { varName: "a" } + } + ] }] }, { @@ -598,7 +676,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "c", action: "defined", additional: ". Allowed unused args must match /^_/u" - } + }, + suggestions: [ + { + output: "function foo(a, _b) { return a; } foo();", + messageId: "removeVar", + data: { varName: "c" } + } + ] }] }, { @@ -612,7 +697,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "_a", action: "defined", additional: ". Allowed unused args must match /[iI]gnored/u" - } + }, + suggestions: [ + { + output: "function foo() { } foo();", + messageId: "removeVar", + data: { varName: "_a" } + } + ] }] }, { @@ -627,131 +719,196 @@ ruleTester.run("no-unused-vars", rule, { varName: "secondItem", action: "assigned a value", additional: ". Allowed unused vars must match /[iI]gnored/u" - } + }, + suggestions: [ + { + output: "var [ firstItemIgnored ] = items;", + messageId: "removeVar", + data: { varName: "secondItem" } + } + ] }] }, // https://github.com/eslint/eslint/issues/15611 { - code: ` - const array = ['a', 'b', 'c']; - const [a, _b, c] = array; - const newArray = [a, c]; - `, + code: "const array = ['a', 'b', 'c']; const [a, _b, c] = array; const newArray = [a, c];", options: [{ destructuredArrayIgnorePattern: "^_" }], languageOptions: { ecmaVersion: 2020 }, errors: [ // should report only `newArray` - { ...assignedError("newArray"), line: 4, column: 19 } + { + ...assignedError("newArray", [{ output: "const array = ['a', 'b', 'c']; const [a, _b, c] = array; ", messageId: "removeVar", data: { varName: "newArray" } }]) + } ] }, { - code: ` - const array = ['a', 'b', 'c', 'd', 'e']; - const [a, _b, c] = array; - `, + code: "const array = ['a', 'b', 'c', 'd', 'e']; const [a, _b, c] = array;", options: [{ destructuredArrayIgnorePattern: "^_" }], languageOptions: { ecmaVersion: 2020 }, errors: [ { - ...assignedError("a", ". Allowed unused elements of array destructuring must match /^_/u"), - line: 3, - column: 20 + ...assignedError( + "a", + [ + { + output: "const array = ['a', 'b', 'c', 'd', 'e']; const [, _b, c] = array;", + messageId: "removeVar", + data: { varName: "a" } + } + ], + ". Allowed unused elements of array destructuring must match /^_/u" + ), + line: 1, + column: 49 }, { - ...assignedError("c", ". Allowed unused elements of array destructuring must match /^_/u"), - line: 3, - column: 27 + ...assignedError( + "c", + [ + { + output: "const array = ['a', 'b', 'c', 'd', 'e']; const [a, _b] = array;", + messageId: "removeVar", + data: { varName: "c" } + } + ], + ". Allowed unused elements of array destructuring must match /^_/u" + ), + line: 1, + column: 56 } ] }, { - code: ` - const array = ['a', 'b', 'c']; - const [a, _b, c] = array; - const fooArray = ['foo']; - const barArray = ['bar']; - const ignoreArray = ['ignore']; - `, + code: "const array = ['a', 'b', 'c'];\nconst [a, _b, c] = array;\nconst fooArray = ['foo'];\nconst barArray = ['bar'];\nconst ignoreArray = ['ignore'];", options: [{ destructuredArrayIgnorePattern: "^_", varsIgnorePattern: "ignore" }], languageOptions: { ecmaVersion: 2020 }, errors: [ { - ...assignedError("a", ". Allowed unused elements of array destructuring must match /^_/u"), - line: 3, - column: 20 + ...assignedError( + "a", + [ + { + output: "const array = ['a', 'b', 'c'];\nconst [, _b, c] = array;\nconst fooArray = ['foo'];\nconst barArray = ['bar'];\nconst ignoreArray = ['ignore'];", + messageId: "removeVar", + data: { varName: "a" } + } + ], + ". Allowed unused elements of array destructuring must match /^_/u" + ), + line: 2, + column: 8 }, { - ...assignedError("c", ". Allowed unused elements of array destructuring must match /^_/u"), - line: 3, - column: 27 + ...assignedError( + "c", + [ + { + output: "const array = ['a', 'b', 'c'];\nconst [a, _b] = array;\nconst fooArray = ['foo'];\nconst barArray = ['bar'];\nconst ignoreArray = ['ignore'];", + messageId: "removeVar", + data: { varName: "c" } + } + ], + ". Allowed unused elements of array destructuring must match /^_/u" + ), + line: 2, + column: 15 }, { - ...assignedError("fooArray", ". Allowed unused vars must match /ignore/u"), - line: 4, - column: 19 + ...assignedError( + "fooArray", + [ + { + output: "const array = ['a', 'b', 'c'];\nconst [a, _b, c] = array;\n\nconst barArray = ['bar'];\nconst ignoreArray = ['ignore'];", + messageId: "removeVar", + data: { varName: "fooArray" } + } + ], + ". Allowed unused vars must match /ignore/u" + ), + line: 3, + column: 7 }, { - ...assignedError("barArray", ". Allowed unused vars must match /ignore/u"), - line: 5, - column: 19 + ...assignedError( + "barArray", + [ + { + output: "const array = ['a', 'b', 'c'];\nconst [a, _b, c] = array;\nconst fooArray = ['foo'];\n\nconst ignoreArray = ['ignore'];", + messageId: "removeVar", + data: { varName: "barArray" } + } + ], + ". Allowed unused vars must match /ignore/u" + ), + line: 4, + column: 7 } ] }, { - code: ` - const array = [obj]; - const [{_a, foo}] = array; - console.log(foo); - `, + code: "const array = [obj]; const [{_a, foo}] = array; console.log(foo);", options: [{ destructuredArrayIgnorePattern: "^_" }], languageOptions: { ecmaVersion: 2020 }, errors: [ { - ...assignedError("_a"), - line: 3, - column: 21 + ...assignedError("_a", [ + { + output: "const array = [obj]; const [{ foo}] = array; console.log(foo);", + messageId: "removeVar", + data: { varName: "_a" } + } + ]), + line: 1, + column: 30 } ] }, { - code: ` - function foo([{_a, bar}]) { - bar; - } - foo(); - `, + code: "function foo([{_a, bar}]) {bar;}foo();", options: [{ destructuredArrayIgnorePattern: "^_" }], languageOptions: { ecmaVersion: 2020 }, errors: [ { - ...definedError("_a"), - line: 2, - column: 28 + ...definedError("_a", [ + { + output: "function foo([{ bar}]) {bar;}foo();", + messageId: "removeVar", + data: { varName: "_a" } + } + ]), + line: 1, + column: 16 } ] }, { - code: ` - let _a, b; - - foo.forEach(item => { - [a, b] = item; - }); - `, + code: "let _a, b; foo.forEach(item => { [a, b] = item; });", options: [{ destructuredArrayIgnorePattern: "^_" }], languageOptions: { ecmaVersion: 2020 }, errors: [ { - ...definedError("_a"), - line: 2, - column: 17 + ...definedError("_a", [ + { + output: "let b; foo.forEach(item => { [a, b] = item; });", + messageId: "removeVar", + data: { varName: "_a" } + } + ]), + line: 1, + column: 5 }, { - ...assignedError("b"), - line: 2, - column: 21 + ...assignedError("b", [ + { + output: "let _a; foo.forEach(item => { [a, b] = item; });", + messageId: "removeVar", + data: { varName: "b" } + } + ]), + line: 1, + column: 9 } ] }, @@ -767,7 +924,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "name", action: "assigned a value", additional: "" - } + }, + suggestions: [ + { + output: "(function(obj) { for ( name in obj ) { i(); return; } })({});", + messageId: "removeVar", + data: { varName: "name" } + } + ] }] }, { @@ -780,7 +944,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "name", action: "assigned a value", additional: "" - } + }, + suggestions: [ + { + output: "(function(obj) { for ( name in obj ) { } })({});", + messageId: "removeVar", + data: { varName: "name" } + } + ] }] }, { @@ -796,6 +967,34 @@ ruleTester.run("no-unused-vars", rule, { } }] }, + { + code: "for ( var { foo } in bar ) { }", + languageOptions: { ecmaVersion: 6 }, + errors: [{ + line: 1, + column: 13, + messageId: "unusedVar", + data: { + varName: "foo", + action: "assigned a value", + additional: "" + } + }] + }, + { + code: "for ( var [ foo ] in bar ) { }", + languageOptions: { ecmaVersion: 6 }, + errors: [{ + line: 1, + column: 13, + messageId: "unusedVar", + data: { + varName: "foo", + action: "assigned a value", + additional: "" + } + }] + }, // For-of loops { @@ -809,7 +1008,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "name", action: "assigned a value", additional: "" - } + }, + suggestions: [ + { + output: "(function(iter) { for ( name of iter ) { i(); return; } })({});", + messageId: "removeVar", + data: { varName: "name" } + } + ] }] }, { @@ -823,7 +1029,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "name", action: "assigned a value", additional: "" - } + }, + suggestions: [ + { + output: "(function(iter) { for ( name of iter ) { } })({});", + messageId: "removeVar", + data: { varName: "name" } + } + ] }] }, { @@ -840,6 +1053,34 @@ ruleTester.run("no-unused-vars", rule, { } }] }, + { + code: "for ( var { foo } of bar ) { }", + languageOptions: { ecmaVersion: 6 }, + errors: [{ + line: 1, + column: 13, + messageId: "unusedVar", + data: { + varName: "foo", + action: "assigned a value", + additional: "" + } + }] + }, + { + code: "for ( var [ foo ] of bar ) { }", + languageOptions: { ecmaVersion: 6 }, + errors: [{ + line: 1, + column: 13, + messageId: "unusedVar", + data: { + varName: "foo", + action: "assigned a value", + additional: "" + } + }] + }, // https://github.com/eslint/eslint/issues/3617 { @@ -914,7 +1155,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "type", action: "assigned a value", additional: "" - } + }, + suggestions: [ + { + output: "const data = { type: 'coords', x: 1, y: 2 };\nconst { ...coords } = data;\n console.log(coords);", + messageId: "removeVar", + data: { varName: "type" } + } + ] } ] }, @@ -933,7 +1181,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "coords", action: "assigned a value", additional: "" - } + }, + suggestions: [ + { + output: "const data = { type: 'coords', x: 2, y: 2 };\nconst { type } = data;\n console.log(type)", + messageId: "removeVar", + data: { varName: "coords" } + } + ] } ] }, @@ -950,7 +1205,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "coords", action: "assigned a value", additional: "" - } + }, + suggestions: [ + { + output: "let type;\n({ type, ...coords } = data);\n console.log(type)", + messageId: "removeVar", + data: { varName: "coords" } + } + ] } ] }, @@ -968,7 +1230,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "coords", action: "assigned a value", additional: "" - } + }, + suggestions: [ + { + output: "const data = { type: 'coords', x: 3, y: 2 };\nconst { type } = data;\n console.log(type)", + messageId: "removeVar", + data: { varName: "coords" } + } + ] } ] }, @@ -986,7 +1255,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "x", action: "assigned a value", additional: "" - } + }, + suggestions: [ + { + output: "const data = { vars: ['x','y'], x: 1, y: 2 };\nconst { ...coords } = data;\n console.log(coords)", + messageId: "removeVar", + data: { varName: "x" } + } + ] } ] }, @@ -1004,7 +1280,14 @@ ruleTester.run("no-unused-vars", rule, { varName: "x", action: "assigned a value", additional: "" - } + }, + suggestions: [ + { + output: "const data = { defaults: { x: 0 }, x: 1, y: 2 };\nconst { ...coords } = data;\n console.log(coords)", + messageId: "removeVar", + data: { varName: "x" } + } + ] } ] }, @@ -1014,7 +1297,7 @@ ruleTester.run("no-unused-vars", rule, { code: "(({a, ...rest}) => {})", options: [{ args: "all", ignoreRestSiblings: true }], languageOptions: { ecmaVersion: 2018 }, - errors: [definedError("rest")] + errors: [definedError("rest", [{ output: "(({a}) => {})", messageId: "removeVar", data: { varName: "rest" } }])] }, // https://github.com/eslint/eslint/issues/3714 @@ -1147,32 +1430,32 @@ ruleTester.run("no-unused-vars", rule, { { code: "export default function(a) {}", languageOptions: { ecmaVersion: 6, sourceType: "module" }, - errors: [definedError("a")] + errors: [definedError("a", [{ output: "export default function() {}", messageId: "removeVar", data: { varName: "a" } }])] }, { code: "export default function(a, b) { console.log(a); }", languageOptions: { ecmaVersion: 6, sourceType: "module" }, - errors: [definedError("b")] + errors: [definedError("b", [{ output: "export default function(a) { console.log(a); }", messageId: "removeVar", data: { varName: "b" } }])] }, { code: "export default (function(a) {});", languageOptions: { ecmaVersion: 6, sourceType: "module" }, - errors: [definedError("a")] + errors: [definedError("a", [{ output: "export default (function() {});", messageId: "removeVar", data: { varName: "a" } }])] }, { code: "export default (function(a, b) { console.log(a); });", languageOptions: { ecmaVersion: 6, sourceType: "module" }, - errors: [definedError("b")] + errors: [definedError("b", [{ output: "export default (function(a) { console.log(a); });", messageId: "removeVar", data: { varName: "b" } }])] }, { code: "export default (a) => {};", languageOptions: { ecmaVersion: 6, sourceType: "module" }, - errors: [definedError("a")] + errors: [definedError("a", [{ output: "export default () => {};", messageId: "removeVar", data: { varName: "a" } }])] }, { code: "export default (a, b) => { console.log(a); };", languageOptions: { ecmaVersion: 6, sourceType: "module" }, - errors: [definedError("b")] + errors: [definedError("b", [{ output: "export default (a) => { console.log(a); };", messageId: "removeVar", data: { varName: "b" } }])] }, // caughtErrors @@ -1188,7 +1471,7 @@ ruleTester.run("no-unused-vars", rule, { { code: "try{}catch(err){};", options: [{ caughtErrors: "all", caughtErrorsIgnorePattern: "^ignore" }], - errors: [definedError("err", ". Allowed unused args must match /^ignore/u")] + errors: [definedError("err", [], ". Allowed unused args must match /^ignore/u")] }, { code: "try{}catch(err){};", @@ -1205,7 +1488,7 @@ ruleTester.run("no-unused-vars", rule, { { code: "try{}catch(ignoreErr){}try{}catch(err){};", options: [{ caughtErrors: "all", caughtErrorsIgnorePattern: "^ignore" }], - errors: [definedError("err", ". Allowed unused args must match /^ignore/u")] + errors: [definedError("err", [], ". Allowed unused args must match /^ignore/u")] }, // multiple try catch both fail @@ -1213,8 +1496,8 @@ ruleTester.run("no-unused-vars", rule, { code: "try{}catch(error){}try{}catch(err){};", options: [{ caughtErrors: "all", caughtErrorsIgnorePattern: "^ignore" }], errors: [ - definedError("error", ". Allowed unused args must match /^ignore/u"), - definedError("err", ". Allowed unused args must match /^ignore/u") + definedError("error", [], ". Allowed unused args must match /^ignore/u"), + definedError("err", [], ". Allowed unused args must match /^ignore/u") ] }, @@ -1244,28 +1527,28 @@ ruleTester.run("no-unused-vars", rule, { { code: "var a = 0; a = a + a;", errors: [assignedError("a")] }, { code: "var a = 0; a += a + 1;", errors: [assignedError("a")] }, { code: "var a = 0; a++;", errors: [assignedError("a")] }, - { code: "function foo(a) { a = a + 1 } foo();", errors: [assignedError("a")] }, - { code: "function foo(a) { a += a + 1 } foo();", errors: [assignedError("a")] }, - { code: "function foo(a) { a++ } foo();", errors: [assignedError("a")] }, + { code: "function foo(a) { a = a + 1 } foo();", errors: [assignedError("a", [{ output: "function foo() { a = a + 1 } foo();", messageId: "removeVar", data: { varName: "a" } }])] }, + { code: "function foo(a) { a += a + 1 } foo();", errors: [assignedError("a", [{ output: "function foo() { a += a + 1 } foo();", messageId: "removeVar", data: { varName: "a" } }])] }, + { code: "function foo(a) { a++ } foo();", errors: [assignedError("a", [{ output: "function foo() { a++ } foo();", messageId: "removeVar", data: { varName: "a" } }])] }, { code: "var a = 3; a = a * 5 + 6;", errors: [assignedError("a")] }, { code: "var a = 2, b = 4; a = a * 2 + b;", errors: [assignedError("a")] }, // https://github.com/eslint/eslint/issues/6576 (For coverage) { code: "function foo(cb) { cb = function(a) { cb(1 + a); }; bar(not_cb); } foo();", - errors: [assignedError("cb")] + errors: [assignedError("cb", [{ output: "function foo() { cb = function(a) { cb(1 + a); }; bar(not_cb); } foo();", messageId: "removeVar", data: { varName: "cb" } }])] }, { code: "function foo(cb) { cb = function(a) { return cb(1 + a); }(); } foo();", - errors: [assignedError("cb")] + errors: [assignedError("cb", [{ output: "function foo() { cb = function(a) { return cb(1 + a); }(); } foo();", messageId: "removeVar", data: { varName: "cb" } }])] }, { code: "function foo(cb) { cb = (function(a) { cb(1 + a); }, cb); } foo();", - errors: [assignedError("cb")] + errors: [assignedError("cb", [{ output: "function foo() { cb = (function(a) { cb(1 + a); }, cb); } foo();", messageId: "removeVar", data: { varName: "cb" } }])] }, { code: "function foo(cb) { cb = (0, function(a) { cb(1 + a); }); } foo();", - errors: [assignedError("cb")] + errors: [assignedError("cb", [{ output: "function foo() { cb = (0, function(a) { cb(1 + a); }); } foo();", messageId: "removeVar", data: { varName: "cb" } }])] }, // https://github.com/eslint/eslint/issues/6646 @@ -1278,7 +1561,22 @@ ruleTester.run("no-unused-vars", rule, { " foo()", "}" ].join("\n"), - errors: [assignedError("b")] + errors: [ + assignedError("b", [ + { + output: [ + "while (a) {", + " function foo() {", + " b = b + 1;", + " }", + " foo()", + "}" + ].join("\n"), + messageId: "removeVar", + data: { varName: "b" } + } + ]) + ] }, // https://github.com/eslint/eslint/issues/7124 @@ -1286,8 +1584,8 @@ ruleTester.run("no-unused-vars", rule, { code: "(function(a, b, c) {})", options: [{ argsIgnorePattern: "c" }], errors: [ - definedError("a", ". Allowed unused args must match /c/u"), - definedError("b", ". Allowed unused args must match /c/u") + definedError("a", [{ output: "(function( b, c) {})", messageId: "removeVar", data: { varName: "a" } }], ". Allowed unused args must match /c/u"), + definedError("b", [{ output: "(function(a, c) {})", messageId: "removeVar", data: { varName: "b" } }], ". Allowed unused args must match /c/u") ] }, { @@ -1295,8 +1593,8 @@ ruleTester.run("no-unused-vars", rule, { options: [{ argsIgnorePattern: "[cd]" }], languageOptions: { ecmaVersion: 6 }, errors: [ - definedError("a", ". Allowed unused args must match /[cd]/u"), - definedError("b", ". Allowed unused args must match /[cd]/u") + definedError("a", [{ output: "(function( b, {c, d}) {})", messageId: "removeVar", data: { varName: "a" } }], ". Allowed unused args must match /[cd]/u"), + definedError("b", [{ output: "(function(a, {c, d}) {})", messageId: "removeVar", data: { varName: "b" } }], ". Allowed unused args must match /[cd]/u") ] }, { @@ -1304,9 +1602,9 @@ ruleTester.run("no-unused-vars", rule, { options: [{ argsIgnorePattern: "c" }], languageOptions: { ecmaVersion: 6 }, errors: [ - definedError("a", ". Allowed unused args must match /c/u"), - definedError("b", ". Allowed unused args must match /c/u"), - definedError("d", ". Allowed unused args must match /c/u") + definedError("a", [{ output: "(function( b, {c, d}) {})", messageId: "removeVar", data: { varName: "a" } }], ". Allowed unused args must match /c/u"), + definedError("b", [{ output: "(function(a, {c, d}) {})", messageId: "removeVar", data: { varName: "b" } }], ". Allowed unused args must match /c/u"), + definedError("d", [{ output: "(function(a, b, {c}) {})", messageId: "removeVar", data: { varName: "d" } }], ". Allowed unused args must match /c/u") ] }, { @@ -1314,9 +1612,9 @@ ruleTester.run("no-unused-vars", rule, { options: [{ argsIgnorePattern: "d" }], languageOptions: { ecmaVersion: 6 }, errors: [ - definedError("a", ". Allowed unused args must match /d/u"), - definedError("b", ". Allowed unused args must match /d/u"), - definedError("c", ". Allowed unused args must match /d/u") + definedError("a", [{ output: "(function( b, {c, d}) {})", messageId: "removeVar", data: { varName: "a" } }], ". Allowed unused args must match /d/u"), + definedError("b", [{ output: "(function(a, {c, d}) {})", messageId: "removeVar", data: { varName: "b" } }], ". Allowed unused args must match /d/u"), + definedError("c", [{ output: "(function(a, b, { d}) {})", messageId: "removeVar", data: { varName: "c" } }], ". Allowed unused args must match /d/u") ] }, { @@ -1340,31 +1638,28 @@ ruleTester.run("no-unused-vars", rule, { code: "(function ({ a }, b ) { return b; })();", languageOptions: { ecmaVersion: 2015 }, errors: [ - definedError("a") + definedError("a", [{ output: "(function ( b ) { return b; })();", messageId: "removeVar", data: { varName: "a" } }]) ] }, { code: "(function ({ a }, { b, c } ) { return b; })();", languageOptions: { ecmaVersion: 2015 }, errors: [ - definedError("a"), - definedError("c") + definedError("a", [{ output: "(function ( { b, c } ) { return b; })();", messageId: "removeVar", data: { varName: "a" } }]), + definedError("c", [{ output: "(function ({ a }, { b } ) { return b; })();", messageId: "removeVar", data: { varName: "c" } }]) ] }, // https://github.com/eslint/eslint/issues/14325 { - code: `let x = 0; - x++, x = 0;`, + code: "let x = 0;\nx++, x = 0;", languageOptions: { ecmaVersion: 2015 }, - errors: [{ ...assignedError("x"), line: 2, column: 18 }] + errors: [{ ...assignedError("x"), line: 2, column: 6 }] }, { - code: `let x = 0; - x++, x = 0; - x=3;`, + code: "let x = 0;\nx++, x = 0;\nx=3;", languageOptions: { ecmaVersion: 2015 }, - errors: [{ ...assignedError("x"), line: 3, column: 13 }] + errors: [{ ...assignedError("x"), line: 3, column: 1 }] }, { code: "let x = 0; x++, 0;", @@ -1419,26 +1714,31 @@ ruleTester.run("no-unused-vars", rule, { // https://github.com/eslint/eslint/issues/14866 { - code: `let z = 0; - z = z + 1, z = 2; - `, + code: "let z = 0;\nz = z + 1, z = 2;", languageOptions: { ecmaVersion: 2020 }, - errors: [{ ...assignedError("z"), line: 2, column: 24 }] + errors: [ + { + ...assignedError("z"), + line: 2, + column: 12 + } + ] }, { - code: `let z = 0; - z = z+1, z = 2; - z = 3;`, + code: "let z = 0;\nz = z+1, z = 2;\nz = 3;", languageOptions: { ecmaVersion: 2020 }, - errors: [{ ...assignedError("z"), line: 3, column: 13 }] + errors: [ + { + ...assignedError("z"), + line: 3, + column: 1 + } + ] }, { - code: `let z = 0; - z = z+1, z = 2; - z = z+3; - `, + code: "let z = 0;\nz = z+1, z = 2;\nz = z+3;", languageOptions: { ecmaVersion: 2020 }, - errors: [{ ...assignedError("z"), line: 3, column: 13 }] + errors: [{ ...assignedError("z"), line: 3, column: 1 }] }, { code: "let x = 0; 0, x = x+1;", @@ -1469,31 +1769,31 @@ ruleTester.run("no-unused-vars", rule, { code: "(function ({ a, b }, { c } ) { return b; })();", languageOptions: { ecmaVersion: 2015 }, errors: [ - definedError("a"), - definedError("c") + definedError("a", [{ output: "(function ({ b }, { c } ) { return b; })();", messageId: "removeVar", data: { varName: "a" } }]), + definedError("c", [{ output: "(function ({ a, b } ) { return b; })();", messageId: "removeVar", data: { varName: "c" } }]) ] }, { code: "(function ([ a ], b ) { return b; })();", languageOptions: { ecmaVersion: 2015 }, errors: [ - definedError("a") + definedError("a", [{ output: "(function ( b ) { return b; })();", messageId: "removeVar", data: { varName: "a" } }]) ] }, { code: "(function ([ a ], [ b, c ] ) { return b; })();", languageOptions: { ecmaVersion: 2015 }, errors: [ - definedError("a"), - definedError("c") + definedError("a", [{ output: "(function ( [ b, c ] ) { return b; })();", messageId: "removeVar", data: { varName: "a" } }]), + definedError("c", [{ output: "(function ([ a ], [ b ] ) { return b; })();", messageId: "removeVar", data: { varName: "c" } }]) ] }, { code: "(function ([ a, b ], [ c ] ) { return b; })();", languageOptions: { ecmaVersion: 2015 }, errors: [ - definedError("a"), - definedError("c") + definedError("a", [{ output: "(function ([ , b ], [ c ] ) { return b; })();", messageId: "removeVar", data: { varName: "a" } }]), + definedError("c", [{ output: "(function ([ a, b ] ) { return b; })();", messageId: "removeVar", data: { varName: "c" } }]) ] }, @@ -1501,33 +1801,32 @@ ruleTester.run("no-unused-vars", rule, { { code: "(function(_a) {})();", options: [{ args: "all", varsIgnorePattern: "^_" }], - errors: [definedError("_a")] + errors: [definedError("_a", [{ output: "(function() {})();", messageId: "removeVar", data: { varName: "_a" } }])] }, { code: "(function(_a) {})();", options: [{ args: "all", caughtErrorsIgnorePattern: "^_" }], - errors: [definedError("_a")] + errors: [definedError("_a", [{ output: "(function() {})();", messageId: "removeVar", data: { varName: "_a" } }])] }, // https://github.com/eslint/eslint/issues/10982 { code: "var a = function() { a(); };", - errors: [{ ...assignedError("a"), line: 1, column: 5 }] + errors: [{ ...assignedError("a", [{ output: "", messageId: "removeVar", data: { varName: "a" } }]), line: 1, column: 5 }] }, { code: "var a = function(){ return function() { a(); } };", - errors: [{ ...assignedError("a"), line: 1, column: 5 }] + errors: [{ ...assignedError("a", [{ output: "", messageId: "removeVar", data: { varName: "a" } }]), line: 1, column: 5 }] }, { code: "const a = () => () => { a(); };", languageOptions: { ecmaVersion: 2015 }, - errors: [{ ...assignedError("a"), line: 1, column: 7 }] + errors: [{ ...assignedError("a", [{ output: "", messageId: "removeVar", data: { varName: "a" } }]), line: 1, column: 7 }] }, { - code: `let myArray = [1,2,3,4].filter((x) => x == 0); - myArray = myArray.filter((x) => x == 1);`, + code: "let myArray = [1,2,3,4].filter((x) => x == 0);\nmyArray = myArray.filter((x) => x == 1);", languageOptions: { ecmaVersion: 2015 }, - errors: [{ ...assignedError("myArray"), line: 2, column: 5 }] + errors: [{ ...assignedError("myArray"), line: 2, column: 1 }] }, { code: "const a = 1; a += 1;", @@ -1537,7 +1836,7 @@ ruleTester.run("no-unused-vars", rule, { { code: "const a = () => { a(); };", languageOptions: { ecmaVersion: 2015 }, - errors: [{ ...assignedError("a"), line: 1, column: 7 }] + errors: [{ ...assignedError("a", [{ output: "", messageId: "removeVar", data: { varName: "a" } }]), line: 1, column: 7 }] }, // https://github.com/eslint/eslint/issues/14324 @@ -1548,48 +1847,27 @@ ruleTester.run("no-unused-vars", rule, { }, { - code: `let a = 'a'; - a = 10; - function foo(){ - a = 11; - a = () => { - a = 13 - } - }`, + code: "let a = 'a';\na = 10;\nfunction foo(){a = 11;a = () => {a = 13}}", languageOptions: { ecmaVersion: 2020 }, - errors: [{ ...assignedError("a"), line: 2, column: 13 }, { ...definedError("foo"), line: 3, column: 22 }] + errors: [ + { ...assignedError("a"), line: 2, column: 1 }, + { ...definedError("foo", [{ output: "let a = 'a';\na = 10;\n", messageId: "removeVar", data: { varName: "foo" } }]), line: 3, column: 10 } + ] }, { - code: `let foo; - init(); - foo = foo + 2; - function init() { - foo = 1; - }`, + code: "let foo;\ninit();\nfoo = foo + 2;\nfunction init() {foo = 1;}", languageOptions: { ecmaVersion: 2020 }, - errors: [{ ...assignedError("foo"), line: 3, column: 13 }] + errors: [{ ...assignedError("foo", [{ output: "\ninit();\nfoo = foo + 2;\nfunction init() {foo = 1;}", messageId: "removeVar", data: { varName: "foo" } }]), line: 3, column: 1 }] }, { - code: `function foo(n) { - if (n < 2) return 1; - return n * foo(n - 1); - }`, + code: "function foo(n) {\nif (n < 2) return 1;\nreturn n * foo(n - 1);}", languageOptions: { ecmaVersion: 2020 }, - errors: [{ ...definedError("foo"), line: 1, column: 10 }] + errors: [{ ...definedError("foo", [{ output: "", messageId: "removeVar", data: { varName: "foo" } }]), line: 1, column: 10 }] }, { - code: `let c = 'c' -c = 10 -function foo1() { - c = 11 - c = () => { - c = 13 - } -} - -c = foo1`, + code: "let c = 'c';\nc = 10;\nfunction foo1() {c = 11; c = () => { c = 13 }} c = foo1", languageOptions: { ecmaVersion: 2020 }, - errors: [{ ...assignedError("c"), line: 10, column: 1 }] + errors: [{ ...assignedError("c"), line: 3, column: 48 }] }, // ignore class with static initialization block https://github.com/eslint/eslint/issues/17772 @@ -1597,36 +1875,36 @@ c = foo1`, code: "class Foo { static {} }", options: [{ ignoreClassWithStaticInitBlock: false }], languageOptions: { ecmaVersion: 2022 }, - errors: [{ ...definedError("Foo"), line: 1, column: 7 }] + errors: [{ ...definedError("Foo", [{ output: "", messageId: "removeVar", data: { varName: "Foo" } }]), line: 1, column: 7 }] }, { code: "class Foo { static {} }", languageOptions: { ecmaVersion: 2022 }, - errors: [{ ...definedError("Foo"), line: 1, column: 7 }] + errors: [{ ...definedError("Foo", [{ output: "", messageId: "removeVar", data: { varName: "Foo" } }]), line: 1, column: 7 }] }, { code: "class Foo { static { var bar; } }", options: [{ ignoreClassWithStaticInitBlock: true }], languageOptions: { ecmaVersion: 2022 }, - errors: [{ ...definedError("bar"), line: 1, column: 26 }] + errors: [{ ...definedError("bar", [{ output: "class Foo { static { } }", messageId: "removeVar", data: { varName: "bar" } }]), line: 1, column: 26 }] }, { code: "class Foo {}", options: [{ ignoreClassWithStaticInitBlock: true }], languageOptions: { ecmaVersion: 2022 }, - errors: [{ ...definedError("Foo"), line: 1, column: 7 }] + errors: [{ ...definedError("Foo", [{ output: "", messageId: "removeVar", data: { varName: "Foo" } }]), line: 1, column: 7 }] }, { code: "class Foo { static bar; }", options: [{ ignoreClassWithStaticInitBlock: true }], languageOptions: { ecmaVersion: 2022 }, - errors: [{ ...definedError("Foo"), line: 1, column: 7 }] + errors: [{ ...definedError("Foo", [{ output: "", messageId: "removeVar", data: { varName: "Foo" } }]), line: 1, column: 7 }] }, { code: "class Foo { static bar() {} }", options: [{ ignoreClassWithStaticInitBlock: true }], languageOptions: { ecmaVersion: 2022 }, - errors: [{ ...definedError("Foo"), line: 1, column: 7 }] + errors: [{ ...definedError("Foo", [{ output: "", messageId: "removeVar", data: { varName: "Foo" } }]), line: 1, column: 7 }] }, // https://github.com/eslint/eslint/issues/17568 @@ -1645,7 +1923,7 @@ c = foo1`, errors: [usedIgnoredError("_a", ". Used vars must not match /^_/u")] }, { - code: "(function foo(_a) { return _a + 5 })(5)", + code: " (function foo(_a) { return _a + 5 })(5)", options: [{ args: "all", argsIgnorePattern: "^_", reportUsedIgnorePattern: true }], errors: [usedIgnoredError("_a", ". Used args must not match /^_/u")] }, @@ -1673,6 +1951,245 @@ c = foo1`, code: "try{}catch(_err){console.error(_err)}", options: [{ caughtErrors: "all", caughtErrorsIgnorePattern: "^_", reportUsedIgnorePattern: true }], errors: [usedIgnoredError("_err", ". Used args must not match /^_/u")] + }, + { + code: "const [a = aDefault] = foo;", + languageOptions: { ecmaVersion: 6 }, + errors: [assignedError("a", [{ output: "", messageId: "removeVar", data: { varName: "a" } }])] + }, + { + code: "const [[a = aDefault]]= foo;", + languageOptions: { ecmaVersion: 6 }, + errors: [assignedError("a", [{ output: "", messageId: "removeVar", data: { varName: "a" } }])] + }, + { + code: "const [[a = aDefault], b]= foo;", + languageOptions: { ecmaVersion: 6 }, + errors: [ + assignedError("a", [{ output: "const [, b]= foo;", messageId: "removeVar", data: { varName: "a" } }]), + assignedError("b", [{ output: "const [[a = aDefault]]= foo;", messageId: "removeVar", data: { varName: "b" } }]) + ] + }, + { + code: "const [a = aDefault, b] = foo; alert(b);", + languageOptions: { ecmaVersion: 6 }, + errors: [assignedError("a", [{ output: "const [, b] = foo; alert(b);", messageId: "removeVar", data: { varName: "a" } }])] + }, + { + code: "function a([a = aDefault]) { } a();", + languageOptions: { ecmaVersion: 6 }, + errors: [assignedError("a", [{ output: "function a() { } a();", messageId: "removeVar", data: { varName: "a" } }])] + }, + { + code: "function a([[a = aDefault]]) { } a();", + languageOptions: { ecmaVersion: 6 }, + errors: [assignedError("a", [{ output: "function a() { } a();", messageId: "removeVar", data: { varName: "a" } }])] + }, + { + code: "function a([a = aDefault, b]) { alert(b); } a();", + languageOptions: { ecmaVersion: 6 }, + errors: [assignedError("a", [{ output: "function a([, b]) { alert(b); } a();", messageId: "removeVar", data: { varName: "a" } }])] + }, + { + code: "function a([[a = aDefault, b]]) { alert(b); } a();", + languageOptions: { ecmaVersion: 6 }, + errors: [assignedError("a", [{ output: "function a([[, b]]) { alert(b); } a();", messageId: "removeVar", data: { varName: "a" } }])] + }, + { + code: "const { a: a1 } = foo", + languageOptions: { ecmaVersion: 6 }, + errors: [assignedError("a1", [{ output: "", messageId: "removeVar", data: { varName: "a1" } }])] + }, + { + code: "const { a: a1, b: b1 } = foo; alert(b1);", + languageOptions: { ecmaVersion: 6 }, + errors: [assignedError("a1", [{ output: "const { b: b1 } = foo; alert(b1);", messageId: "removeVar", data: { varName: "a1" } }])] + }, + { + code: "function a({ a: a1 }) {} a();", + languageOptions: { ecmaVersion: 6 }, + errors: [definedError("a1", [{ output: "function a() {} a();", messageId: "removeVar", data: { varName: "a1" } }])] + }, + { + code: "const { a: a1 = aDefault } = foo;", + languageOptions: { ecmaVersion: 6 }, + errors: [assignedError("a1", [{ output: "", messageId: "removeVar", data: { varName: "a1" } }])] + }, + { + code: "const [{ a: a1 = aDefault }] = foo;", + languageOptions: { ecmaVersion: 6 }, + errors: [assignedError("a1", [{ output: "", messageId: "removeVar", data: { varName: "a1" } }])] + }, + { + code: "const { [key]: a } = foo;", + languageOptions: { ecmaVersion: 6 }, + errors: [assignedError("a", [{ output: "", messageId: "removeVar", data: { varName: "a" } }])] + }, + { + code: "const [...{ a, b }] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [...{ a }] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [a, ...{ b }] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [a] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [[a, ...{ b }]] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [[a]] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [...[a, b]] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [...[a]] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [a, ...[b]] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [a] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [[a, ...[b]]] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [[a]] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [a, ...[b]] = array; alert(b);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("a", [{ output: "const [, ...[b]] = array; alert(b);", messageId: "removeVar", data: { varName: "a" } }])] + }, + { + code: "const [a, ...[[ b ]]] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [a] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [a, ...[{ b }]] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [a] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "function foo([a, ...[[ b ]]]) {} foo();", + languageOptions: { ecmaVersion: 2023 }, + errors: [ + definedError("a", [{ output: "function foo([, ...[[ b ]]]) {} foo();", messageId: "removeVar", data: { varName: "a" } }]), + definedError("b", [{ output: "function foo([a]) {} foo();", messageId: "removeVar", data: { varName: "b" } }]) + ] + }, + { + code: "function foo([a, ...[{ b }]]) {} foo();", + languageOptions: { ecmaVersion: 2023 }, + errors: [ + definedError("a", [{ output: "function foo([, ...[{ b }]]) {} foo();", messageId: "removeVar", data: { varName: "a" } }]), + definedError("b", [{ output: "function foo([a]) {} foo();", messageId: "removeVar", data: { varName: "b" } }]) + ] + }, + { + code: "function foo(...[[ a ]]) {} foo();", + languageOptions: { ecmaVersion: 2023 }, + errors: [definedError("a", [{ output: "function foo() {} foo();", messageId: "removeVar", data: { varName: "a" } }])] + }, + { + code: "function foo(...[{ a }]) {} foo();", + languageOptions: { ecmaVersion: 2023 }, + errors: [definedError("a", [{ output: "function foo() {} foo();", messageId: "removeVar", data: { varName: "a" } }])] + }, + { + code: "const [a, [b]] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [a] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [[a, [b]]] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [[a]] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [a, [[b]]] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [a] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "function a([[b]]) {} a();", + languageOptions: { ecmaVersion: 2023 }, + errors: [definedError("b", [{ output: "function a() {} a();", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "function a([[b], c]) { alert(c); } a();", + languageOptions: { ecmaVersion: 2023 }, + errors: [definedError("b", [{ output: "function a([, c]) { alert(c); } a();", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [{b}, a] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [, a] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [[{b}, a]] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [[, a]] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [[[{b}], a]] = array; alert(a);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [[, a]] = array; alert(a);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "function a([{b}]) {} a();", + languageOptions: { ecmaVersion: 2023 }, + errors: [definedError("b", [{ output: "function a() {} a();", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "function a([{b}, c]) { alert(c); } a();", + languageOptions: { ecmaVersion: 2023 }, + errors: [definedError("b", [{ output: "function a([, c]) { alert(c); } a();", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const { a: { b }, c } = foo; alert(c);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const { c } = foo; alert(c);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const { a: { b: { c }, d } } = foo; alert(d);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("c", [{ output: "const { a: { d } } = foo; alert(d);", messageId: "removeVar", data: { varName: "c" } }])] + }, + { + code: "const [{ a: { b }, c }] = foo; alert(c);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const [{ c }] = foo; alert(c);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const { a: [{ b }]} = foo;", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const { a: [[ b ]]} = foo;", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const [{ a: [{ b }]}] = foo;", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "const { a: [{ b }], c} = foo; alert(c);", + languageOptions: { ecmaVersion: 2023 }, + errors: [assignedError("b", [{ output: "const { c} = foo; alert(c);", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "function foo({ a: [{ b }]}) {} foo();", + languageOptions: { ecmaVersion: 2023 }, + errors: [definedError("b", [{ output: "function foo() {} foo();", messageId: "removeVar", data: { varName: "b" } }])] + }, + { + code: "function foo({ a: [[ b ]]}) {} foo();", + languageOptions: { ecmaVersion: 2023 }, + errors: [definedError("b", [{ output: "function foo() {} foo();", messageId: "removeVar", data: { varName: "b" } }])] } ] });