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

no-unused-vars: Improve error messages to include the allowed patterns #9176

Merged
merged 1 commit into from Aug 31, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
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
51 changes: 47 additions & 4 deletions lib/rules/no-unused-vars.js
Expand Up @@ -64,8 +64,6 @@ module.exports = {
create(context) {
const sourceCode = context.getSourceCode();

const DEFINED_MESSAGE = "'{{name}}' is defined but never used.";
const ASSIGNED_MESSAGE = "'{{name}}' is assigned a value but never used.";
const REST_PROPERTY_TYPE = /^(?:Experimental)?RestProperty$/;

const config = {
Expand Down Expand Up @@ -100,6 +98,49 @@ module.exports = {
}
}

/**
* Generate the warning message about the variable being
* defined and unused, including the ignore pattern if configured.
* @param {Variable} unusedVar - eslint-scope variable object.
* @returns {string} The warning message to be used with this unused variable.
*/
function getDefinedMessage(unusedVar) {
let type;
let pattern;

if (config.varsIgnorePattern) {
type = "vars";
pattern = config.varsIgnorePattern.toString();
}

if (unusedVar.defs && unusedVar.defs[0] && unusedVar.defs[0].type) {
const defType = unusedVar.defs[0].type;

if (defType === "CatchClause" && config.caughtErrorsIgnorePattern) {
type = "args";
pattern = config.caughtErrorsIgnorePattern.toString();
} else if (defType === "Parameter" && config.argsIgnorePattern) {
type = "args";
pattern = config.argsIgnorePattern.toString();
}
}

const additional = type ? ` Allowed unused ${type} must match ${pattern}.` : "";

return `'{{name}}' is defined but never used.${additional}`;
}

/**
* Generate the warning message about the variable being
* assigned and unused, including the ignore pattern if configured.
* @returns {string} The warning message to be used with this unused variable.
*/
function getAssignedMessage() {
const additional = config.varsIgnorePattern ? ` Allowed unused vars must match ${config.varsIgnorePattern.toString()}.` : "";

return `'{{name}}' is assigned a value but never used.${additional}`;
}

//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
Expand Down Expand Up @@ -586,13 +627,15 @@ module.exports = {
context.report({
node: programNode,
loc: getLocation(unusedVar),
message: DEFINED_MESSAGE,
message: getDefinedMessage(unusedVar),
data: unusedVar
});
} else if (unusedVar.defs.length > 0) {
context.report({
node: unusedVar.identifiers[0],
message: unusedVar.references.some(ref => ref.isWrite()) ? ASSIGNED_MESSAGE : DEFINED_MESSAGE,
message: unusedVar.references.some(ref => ref.isWrite())
? getAssignedMessage()
: getDefinedMessage(unusedVar),
data: unusedVar
});
}
Expand Down
52 changes: 39 additions & 13 deletions tests/lib/rules/no-unused-vars.js
Expand Up @@ -326,11 +326,37 @@ ruleTester.run("no-unused-vars", rule, {
{ code: "/*exported x*/ var { x, y } = z", parserOptions: { ecmaVersion: 6 }, errors: [assignedError("y")] },

// ignore pattern
{ code: "var _a; var b;", options: [{ vars: "all", varsIgnorePattern: "^_" }], errors: [{ message: "'b' is defined but never used.", line: 1, column: 13 }] },
{ code: "var a; function foo() { var _b; var c_; } foo();", options: [{ vars: "local", varsIgnorePattern: "^_" }], errors: [{ message: "'c_' is defined but never used.", line: 1, column: 37 }] },
{ code: "function foo(a, _b) { } foo();", options: [{ args: "all", argsIgnorePattern: "^_" }], errors: [{ message: "'a' is defined but never used.", line: 1, column: 14 }] },
{ code: "function foo(a, _b, c) { return a; } foo();", options: [{ args: "after-used", argsIgnorePattern: "^_" }], errors: [{ message: "'c' is defined but never used.", line: 1, column: 21 }] },
{ code: "var [ firstItemIgnored, secondItem ] = items;", options: [{ vars: "all", varsIgnorePattern: "[iI]gnored" }], parserOptions: { ecmaVersion: 6 }, errors: [{ message: "'secondItem' is assigned a value but never used.", line: 1, column: 25 }] },
{
code: "var _a; var b;",
options: [{ vars: "all", varsIgnorePattern: "^_" }],
errors: [{ message: "'b' is defined but never used. Allowed unused vars must match /^_/.", line: 1, column: 13 }]
},
{
code: "var a; function foo() { var _b; var c_; } foo();",
options: [{ vars: "local", varsIgnorePattern: "^_" }],
errors: [{ message: "'c_' is defined but never used. Allowed unused vars must match /^_/.", line: 1, column: 37 }]
},
{
code: "function foo(a, _b) { } foo();",
options: [{ args: "all", argsIgnorePattern: "^_" }],
errors: [{ message: "'a' is defined but never used. Allowed unused args must match /^_/.", line: 1, column: 14 }]
},
{
code: "function foo(a, _b, c) { return a; } foo();",
options: [{ args: "after-used", argsIgnorePattern: "^_" }],
errors: [{ message: "'c' is defined but never used. Allowed unused args must match /^_/.", line: 1, column: 21 }]
},
{
code: "function foo(_a) { } foo();",
options: [{ args: "all", argsIgnorePattern: "[iI]gnored" }],
errors: [{ message: "'_a' is defined but never used. Allowed unused args must match /[iI]gnored/.", line: 1, column: 14 }]
},
{
code: "var [ firstItemIgnored, secondItem ] = items;",
options: [{ vars: "all", varsIgnorePattern: "[iI]gnored" }],
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "'secondItem' is assigned a value but never used. Allowed unused vars must match /[iI]gnored/.", line: 1, column: 25 }]
},

// for-in loops (see #2342)
{ code: "(function(obj) { var name; for ( name in obj ) { i(); return; } })({});", errors: [{ message: "'name' is assigned a value but never used.", line: 1, column: 22 }] },
Expand Down Expand Up @@ -491,23 +517,23 @@ ruleTester.run("no-unused-vars", rule, {
{
code: "try{}catch(err){};",
options: [{ caughtErrors: "all", caughtErrorsIgnorePattern: "^ignore" }],
errors: [{ message: "'err' is defined but never used." }]
errors: [{ message: "'err' is defined but never used. Allowed unused args must match /^ignore/." }]
},

// multiple try catch with one success
{
code: "try{}catch(ignoreErr){}try{}catch(err){};",
options: [{ caughtErrors: "all", caughtErrorsIgnorePattern: "^ignore" }],
errors: [{ message: "'err' is defined but never used." }]
errors: [{ message: "'err' is defined but never used. Allowed unused args must match /^ignore/." }]
},

// multiple try catch both fail
{
code: "try{}catch(error){}try{}catch(err){};",
options: [{ caughtErrors: "all", caughtErrorsIgnorePattern: "^ignore" }],
errors: [
{ message: "'error' is defined but never used." },
{ message: "'err' is defined but never used." }
{ message: "'error' is defined but never used. Allowed unused args must match /^ignore/." },
{ message: "'err' is defined but never used. Allowed unused args must match /^ignore/." }
]
},

Expand Down Expand Up @@ -578,25 +604,25 @@ ruleTester.run("no-unused-vars", rule, {
{
code: "(function(a, b, c) {})",
options: [{ argsIgnorePattern: "c" }],
errors: [{ message: "'b' is defined but never used." }]
errors: [{ message: "'b' is defined but never used. Allowed unused args must match /c/." }]
},
{
code: "(function(a, b, {c, d}) {})",
options: [{ argsIgnorePattern: "[cd]" }],
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "'b' is defined but never used." }]
errors: [{ message: "'b' is defined but never used. Allowed unused args must match /[cd]/." }]
},
{
code: "(function(a, b, {c, d}) {})",
options: [{ argsIgnorePattern: "c" }],
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "'d' is defined but never used." }]
errors: [{ message: "'d' is defined but never used. Allowed unused args must match /c/." }]
},
{
code: "(function(a, b, {c, d}) {})",
options: [{ argsIgnorePattern: "d" }],
parserOptions: { ecmaVersion: 6 },
errors: [{ message: "'c' is defined but never used." }]
errors: [{ message: "'c' is defined but never used. Allowed unused args must match /d/." }]
},
{
code: "/*global\rfoo*/",
Expand Down