Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 5e509d0

Browse files
authored
fix(no-negated-v-if-condition): swap elements (#2941)
1 parent f9dcbda commit 5e509d0

File tree

3 files changed

+229
-90
lines changed

3 files changed

+229
-90
lines changed

‎.changeset/tired-emus-matter.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'eslint-plugin-vue': patch
3+
---
4+
5+
Fixed `no-negated-v-if-condition` rule to swap entire elements

‎lib/rules/no-negated-v-if-condition.js‎

Lines changed: 82 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
5671
module.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-
yieldfixer.replaceTextRange(
188-
[elseElement.startTag.range[1],elseElement.endTag.range[0]],
189-
ifContent
188+
constelseText=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

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /