-
-
Notifications
You must be signed in to change notification settings - Fork 681
/
Copy pathno-unused-vars.js
146 lines (136 loc) · 3.94 KB
/
no-unused-vars.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/**
* @fileoverview disallow unused variable definitions of v-for directives or scope attributes.
* @author 薛定谔的猫<[email protected]>
*/
'use strict'
const utils = require('../utils')
/**
* @typedef {VVariable['kind']} VariableKind
*/
/**
* Groups variables by directive kind.
* @param {VElement} node The element node
* @returns { { [kind in VariableKind]?: VVariable[] } } The variables of grouped by directive kind.
*/
function groupingVariables(node) {
/** @type { { [kind in VariableKind]?: VVariable[] } } */
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 {VVariable} 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 {ASTNode | null} */
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
}
module.exports = {
meta: {
type: 'suggestion',
docs: {
description:
'disallow unused variable definitions of v-for directives or scope attributes',
categories: ['vue3-essential', 'vue2-essential'],
url: 'https://eslint.vuejs.org/rules/no-unused-vars.html'
},
fixable: null,
hasSuggestions: true,
schema: [
{
type: 'object',
properties: {
ignorePattern: {
type: 'string'
}
},
additionalProperties: false
}
],
messages: {
unusedVariable: "'{{name}}' is defined but never used.",
replaceWithUnderscore:
'Replace `{{name}}` with `_{{name}}` to ignore the unused variable.'
}
},
/** @param {RuleContext} context */
create(context) {
const option = context.options[0] || {}
const ignorePattern = option.ignorePattern
/** @type {RegExp | null} */
let ignoreRegEx = null
if (ignorePattern) {
ignoreRegEx = new RegExp(ignorePattern, 'u')
}
return utils.defineTemplateBodyVisitor(context, {
/**
* @param {VElement} node
*/
VElement(node) {
const vars = groupingVariables(node)
for (const variables of Object.values(vars)) {
if (!variables) {
continue
}
let hasAfterUsed = false
for (let i = variables.length - 1; i >= 0; i--) {
const variable = variables[i]
if (variable.references.length > 0) {
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,
messageId: 'unusedVariable',
data: {
name: variable.id.name
},
suggest:
ignorePattern === '^_'
? [
{
messageId: 'replaceWithUnderscore',
data: { name: variable.id.name },
fix(fixer) {
return fixer.replaceText(
variable.id,
`_${variable.id.name}`
)
}
}
]
: []
})
}
}
}
})
}
}