@@ -53,6 +53,21 @@ function isDirectlyFollowedByElse(element) {
5353 return nextElement ? utils . hasDirective ( nextElement , 'else' ) : false
5454}
5555
56+ /**
57+ * @param {VElement } element
58+ */
59+ function getDirective ( element ) {
60+ return /** @type {VIfDirective|undefined } */ (
61+ element . startTag . attributes . find (
62+ ( attr ) =>
63+ attr . directive &&
64+ attr . key . name &&
65+ attr . key . name . name &&
66+ [ 'if' , 'else-if' , 'else' ] . includes ( attr . key . name . name )
67+ )
68+ )
69+ }
70+
5671module . exports = {
5772 meta : {
5873 type : 'suggestion' ,
@@ -73,9 +88,37 @@ module.exports = {
7388 /** @param {RuleContext } context */
7489 create ( context ) {
7590 const sourceCode = context . getSourceCode ( )
76- const templateTokens =
77- sourceCode . parserServices . getTemplateBodyTokenStore &&
78- sourceCode . parserServices . getTemplateBodyTokenStore ( )
91+
92+ const processedPairs = new Set ( )
93+
94+ /**
95+ * @param {Expression } expression
96+ * @returns {string }
97+ */
98+ function getConvertedCondition ( expression ) {
99+ if (
100+ expression . type === 'UnaryExpression' &&
101+ expression . operator === '!'
102+ ) {
103+ return sourceCode . text . slice (
104+ expression . range [ 0 ] + 1 ,
105+ expression . range [ 1 ]
106+ )
107+ }
108+
109+ if ( expression . type === 'BinaryExpression' ) {
110+ const left = sourceCode . getText ( expression . left )
111+ const right = sourceCode . getText ( expression . right )
112+
113+ if ( expression . operator === '!=' ) {
114+ return `${ left } == ${ right } `
115+ } else if ( expression . operator === '!==' ) {
116+ return `${ left } === ${ right } `
117+ }
118+ }
119+
120+ return sourceCode . getText ( expression )
121+ }
79122
80123 /**
81124 * @param {VIfDirective } node
@@ -100,94 +143,67 @@ module.exports = {
100143 return
101144 }
102145
146+ const pairKey = `${ element . range [ 0 ] } -${ elseElement . range [ 0 ] } `
147+ if ( processedPairs . has ( pairKey ) ) {
148+ return
149+ }
150+ processedPairs . add ( pairKey )
151+
103152 context . report ( {
104153 node : expression ,
105154 messageId : 'negatedCondition' ,
106155 suggest : [
107156 {
108157 messageId : 'fixNegatedCondition' ,
109158 * fix ( fixer ) {
110- yield * convertNegatedCondition ( fixer , expression )
111- yield * swapElementContents ( fixer , element , elseElement )
159+ yield * swapElements ( fixer , element , elseElement , expression )
112160 }
113161 }
114162 ]
115163 } )
116164 }
117165
118- /**
119- * @param {RuleFixer } fixer
120- * @param {Expression } expression
121- */
122- function * convertNegatedCondition ( fixer , expression ) {
123- if (
124- expression . type === 'UnaryExpression' &&
125- expression . operator === '!'
126- ) {
127- const token = templateTokens . getFirstToken ( expression )
128- if ( token ?. type === 'Punctuator' && token . value === '!' ) {
129- yield fixer . remove ( token )
130- }
131- return
132- }
133-
134- if ( expression . type === 'BinaryExpression' ) {
135- const operatorToken = templateTokens . getTokenAfter (
136- expression . left ,
137- ( token ) =>
138- token ?. type === 'Punctuator' && token . value === expression . operator
139- )
140-
141- if ( ! operatorToken ) return
142-
143- if ( expression . operator === '!=' ) {
144- yield fixer . replaceText ( operatorToken , '==' )
145- } else if ( expression . operator === '!==' ) {
146- yield fixer . replaceText ( operatorToken , '===' )
147- }
148- }
149- }
150-
151- /**
152- * @param {VElement } element
153- * @returns {string }
154- */
155- function getElementContent ( element ) {
156- if ( element . children . length === 0 || ! element . endTag ) {
157- return ''
158- }
159-
160- const contentStart = element . startTag . range [ 1 ]
161- const contentEnd = element . endTag . range [ 0 ]
162-
163- return sourceCode . text . slice ( contentStart , contentEnd )
164- }
165-
166166 /**
167167 * @param {RuleFixer } fixer
168168 * @param {VElement } ifElement
169169 * @param {VElement } elseElement
170+ * @param {Expression } expression
170171 */
171- function * swapElementContents ( fixer , ifElement , elseElement ) {
172- if ( ! ifElement . endTag || ! elseElement . endTag ) {
173- return
174- }
172+ function * swapElements ( fixer , ifElement , elseElement , expression ) {
173+ const convertedCondition = getConvertedCondition ( expression )
175174
176- const ifContent = getElementContent ( ifElement )
177- const elseContent = getElementContent ( elseElement )
175+ const ifDir = getDirective ( ifElement )
176+ const elseDir = getDirective ( elseElement )
178177
179- if ( ifContent === elseContent ) {
178+ if ( ! ifDir || ! elseDir ) {
180179 return
181180 }
182181
183- yield fixer . replaceTextRange (
184- [ ifElement . startTag . range [ 1 ] , ifElement . endTag . range [ 0 ] ] ,
185- elseContent
182+ const ifDirectiveName = ifDir . key . name . name
183+
184+ const ifText = sourceCode . text . slice (
185+ ifElement . range [ 0 ] ,
186+ ifElement . range [ 1 ]
186187 )
187- yield fixer . replaceTextRange (
188- [ elseElement . startTag . range [ 1 ] , elseElement . endTag . range [ 0 ] ] ,
189- ifContent
188+ const elseText = sourceCode . text . slice (
189+ elseElement . range [ 0 ] ,
190+ elseElement . range [ 1 ]
190191 )
192+
193+ const newIfDirective = `v-${ ifDirectiveName } ="${ convertedCondition } "`
194+ const newIfText =
195+ elseText . slice ( 0 , elseDir . range [ 0 ] - elseElement . range [ 0 ] ) +
196+ newIfDirective +
197+ elseText . slice ( elseDir . range [ 1 ] - elseElement . range [ 0 ] )
198+
199+ const newElseDirective = 'v-else'
200+ const newElseText =
201+ ifText . slice ( 0 , ifDir . range [ 0 ] - ifElement . range [ 0 ] ) +
202+ newElseDirective +
203+ ifText . slice ( ifDir . range [ 1 ] - ifElement . range [ 0 ] )
204+
205+ yield fixer . replaceTextRange ( ifElement . range , newIfText )
206+ yield fixer . replaceTextRange ( elseElement . range , newElseText )
191207 }
192208
193209 return utils . defineTemplateBodyVisitor ( context , {
0 commit comments