diff --git a/lib/rules/no-unused-vars.js b/lib/rules/no-unused-vars.js
index 37356c9c1..e808ee7f9 100644
--- a/lib/rules/no-unused-vars.js
+++ b/lib/rules/no-unused-vars.js
@@ -6,6 +6,58 @@
const utils = require('../utils')
+/**
+ * @typedef {import('vue-eslint-parser').AST.Node} Node
+ * @typedef {import('vue-eslint-parser').AST.VElement} VElement
+ * @typedef {import('vue-eslint-parser').AST.Variable} Variable
+ */
+/**
+ * @typedef {Variable['kind']} VariableKind
+ */
+
+// ------------------------------------------------------------------------------
+// Helpers
+// ------------------------------------------------------------------------------
+
+/**
+ * Groups variables by directive kind.
+ * @param {VElement} node The element node
+ * @returns { { [kind in VariableKind]?: Variable[] } } The variables of grouped by directive kind.
+ */
+function groupingVariables(node) {
+ /** @type { { [kind in VariableKind]?: Variable[] } } */
+ const result = {}
+ for (const variable of node.variables) {
+ const vars = result[variable.kind] || (result[variable.kind] = [])
+ vars.push(variable)
+ }
+ return result
+}
+
+/**
+ * Checks if the given variable was defined by destructuring.
+ * @param {Variable} variable the given variable to check
+ * @returns {boolean} `true` if the given variable was defined by destructuring.
+ */
+function isDestructuringVar(variable) {
+ const node = variable.id
+ /** @type {Node} */
+ let parent = node.parent
+ while (parent) {
+ if (
+ parent.type === 'VForExpression' ||
+ parent.type === 'VSlotScopeExpression'
+ ) {
+ return false
+ }
+ if (parent.type === 'Property' || parent.type === 'ArrayPattern') {
+ return true
+ }
+ parent = parent.parent
+ }
+ return false
+}
+
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
@@ -41,38 +93,52 @@ module.exports = {
ignoreRegEx = new RegExp(ignorePattern, 'u')
}
return utils.defineTemplateBodyVisitor(context, {
+ /**
+ * @param {VElement} node
+ */
VElement(node) {
- const variables = node.variables
- for (let i = variables.length - 1; i >= 0; i--) {
- const variable = variables[i]
+ const vars = groupingVariables(node)
+ for (const variables of Object.values(vars)) {
+ let hasAfterUsed = false
- if (variable.references.length) {
- break
- }
+ for (let i = variables.length - 1; i >= 0; i--) {
+ const variable = variables[i]
- if (ignoreRegEx != null && ignoreRegEx.test(variable.id.name)) {
- continue
- }
- context.report({
- node: variable.id,
- loc: variable.id.loc,
- message: `'{{name}}' is defined but never used.`,
- data: variable.id,
- suggest:
- ignorePattern === '^_'
- ? [
- {
- desc: `Replace the ${variable.id.name} with _${variable.id.name}`,
- fix(fixer) {
- return fixer.replaceText(
- variable.id,
- `_${variable.id.name}`
- )
+ if (variable.references.length) {
+ hasAfterUsed = true
+ continue
+ }
+
+ if (ignoreRegEx != null && ignoreRegEx.test(variable.id.name)) {
+ continue
+ }
+
+ if (hasAfterUsed && !isDestructuringVar(variable)) {
+ // If a variable after the variable is used, it will be skipped.
+ continue
+ }
+
+ context.report({
+ node: variable.id,
+ loc: variable.id.loc,
+ message: `'{{name}}' is defined but never used.`,
+ data: variable.id,
+ suggest:
+ ignorePattern === '^_'
+ ? [
+ {
+ desc: `Replace the ${variable.id.name} with _${variable.id.name}`,
+ fix(fixer) {
+ return fixer.replaceText(
+ variable.id,
+ `_${variable.id.name}`
+ )
+ }
}
- }
- ]
- : []
- })
+ ]
+ : []
+ })
+ }
}
}
})
diff --git a/tests/lib/rules/no-unused-vars.js b/tests/lib/rules/no-unused-vars.js
index 0c1b85e55..81df799bb 100644
--- a/tests/lib/rules/no-unused-vars.js
+++ b/tests/lib/rules/no-unused-vars.js
@@ -162,6 +162,58 @@ tester.run('no-unused-vars', rule, {
code: '',
options: [{ ignorePattern: '^_' }],
errors: ["'a' is defined but never used."]
+ },
+ {
+ code:
+ '{{d}}',
+ errors: ["'a' is defined but never used."]
+ },
+ {
+ code:
+ '{{a}}',
+ errors: ["'i' is defined but never used."]
+ },
+ {
+ code:
+ '{{i}}',
+ errors: ["'a' is defined but never used."]
+ },
+ {
+ code:
+ '{{f}}
',
+ errors: [
+ "'a' is defined but never used.",
+ "'b' is defined but never used.",
+ "'c' is defined but never used.",
+ "'d' is defined but never used."
+ ]
+ },
+ {
+ code:
+ '{{f}}
',
+ errors: [
+ "'a' is defined but never used.",
+ "'b' is defined but never used.",
+ "'d' is defined but never used."
+ ]
+ },
+ {
+ code:
+ '{{d}}',
+ errors: [
+ "'a' is defined but never used.",
+ "'b' is defined but never used.",
+ "'c' is defined but never used."
+ ]
+ },
+ {
+ code:
+ '{{f}}
',
+ errors: [
+ "'a' is defined but never used.",
+ "'bar' is defined but never used.",
+ "'d' is defined but never used."
+ ]
}
]
})