@@ -12,7 +12,7 @@ const utils = require('../utils')
12
12
* @param {Expression } [expression]
13
13
* @return {IterableIterator<{ node: Literal | TemplateElement }> }
14
14
*/
15
- function * extractDuplicateNode ( node , expression ) {
15
+ function * extractClassNodes ( node , expression ) {
16
16
const nodeExpression = expression ?? node . value ?. expression
17
17
if ( ! nodeExpression ) return
18
18
@@ -25,8 +25,7 @@ function* extractDuplicateNode(node, expression) {
25
25
for ( const prop of nodeExpression . properties ) {
26
26
if (
27
27
prop . type === 'Property' &&
28
- prop . key &&
29
- prop . key . type === 'Literal' &&
28
+ prop . key ?. type === 'Literal' &&
30
29
typeof prop . key . value === 'string' &&
31
30
prop . key . value . includes ( ' ' )
32
31
) {
@@ -39,28 +38,28 @@ function* extractDuplicateNode(node, expression) {
39
38
for ( const element of nodeExpression . elements ) {
40
39
if ( ! element || element . type === 'SpreadElement' ) continue
41
40
42
- yield * extractDuplicateNode ( node , element )
41
+ yield * extractClassNodes ( node , element )
43
42
}
44
43
break
45
44
}
46
45
case 'ConditionalExpression' : {
47
- yield * extractDuplicateNode ( node , nodeExpression . consequent )
48
- yield * extractDuplicateNode ( node , nodeExpression . alternate )
46
+ yield * extractClassNodes ( node , nodeExpression . consequent )
47
+ yield * extractClassNodes ( node , nodeExpression . alternate )
49
48
break
50
49
}
51
50
case 'TemplateLiteral' : {
52
51
for ( const quasi of nodeExpression . quasis ) {
53
52
yield { node : quasi }
54
53
}
55
54
for ( const expr of nodeExpression . expressions ) {
56
- yield * extractDuplicateNode ( node , expr )
55
+ yield * extractClassNodes ( node , expr )
57
56
}
58
57
break
59
58
}
60
59
case 'BinaryExpression' : {
61
60
if ( nodeExpression . operator === '+' ) {
62
- yield * extractDuplicateNode ( node , nodeExpression . left )
63
- yield * extractDuplicateNode ( node , nodeExpression . right )
61
+ yield * extractClassNodes ( node , nodeExpression . left )
62
+ yield * extractClassNodes ( node , nodeExpression . right )
64
63
}
65
64
break
66
65
}
@@ -71,7 +70,8 @@ function* extractDuplicateNode(node, expression) {
71
70
* @param {string } raw - raw class names string including quotes
72
71
* @returns {string }
73
72
*/
74
- function dedupePreserveSpaces ( raw ) {
73
+ function removeDuplicateClassNames ( raw ) {
74
+ const quote = raw [ 0 ]
75
75
const inner = raw . slice ( 1 , - 1 )
76
76
const tokens = inner . split ( / ( \s + ) / )
77
77
@@ -128,7 +128,6 @@ function dedupePreserveSpaces(raw) {
128
128
}
129
129
}
130
130
131
- const quote = raw [ 0 ]
132
131
return quote + kept . join ( '' ) + quote
133
132
}
134
133
@@ -152,7 +151,7 @@ module.exports = {
152
151
* @param {VLiteral | Literal | TemplateElement | null } node
153
152
*/
154
153
function reportDuplicateClasses ( node ) {
155
- if ( ! node || ! node . value ) return
154
+ if ( ! node ? .value ) return
156
155
157
156
const classList =
158
157
typeof node . value === 'object' && 'raw' in node . value
@@ -165,29 +164,26 @@ module.exports = {
165
164
if ( classNames . length <= 1 ) return
166
165
167
166
const seen = new Set ( )
168
- /** @type {string[] } */
169
- const duplicates = [ ]
167
+ const duplicates = new Set ( )
170
168
171
169
for ( const className of classNames ) {
172
170
if ( seen . has ( className ) ) {
173
- if ( ! duplicates . includes ( className ) ) {
174
- duplicates . push ( className )
175
- }
171
+ duplicates . add ( className )
176
172
} else {
177
173
seen . add ( className )
178
174
}
179
175
}
180
176
181
- if ( duplicates . length === 0 ) return
177
+ if ( duplicates . size === 0 ) return
182
178
183
179
context . report ( {
184
180
node,
185
181
messageId : 'duplicateClassName' ,
186
- data : { name : duplicates . join ( ', ' ) } ,
182
+ data : { name : [ ... duplicates ] . join ( ', ' ) } ,
187
183
fix : ( fixer ) => {
188
184
const sourceCode = context . getSourceCode ( )
189
185
const raw = sourceCode . text . slice ( node . range [ 0 ] , node . range [ 1 ] )
190
- return fixer . replaceText ( node , dedupePreserveSpaces ( raw ) )
186
+ return fixer . replaceText ( node , removeDuplicateClassNames ( raw ) )
191
187
}
192
188
} )
193
189
}
@@ -203,7 +199,7 @@ module.exports = {
203
199
"VAttribute[directive=true][key.argument.name='class'][value.type='VExpressionContainer']" (
204
200
node
205
201
) {
206
- for ( const { node : reportNode } of extractDuplicateNode ( node ) ) {
202
+ for ( const { node : reportNode } of extractClassNodes ( node ) ) {
207
203
reportDuplicateClasses ( reportNode )
208
204
}
209
205
}
0 commit comments