Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-vue-conditional-newline-comment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@biomejs/biome": patch
---

Fixed several bugs in Vue conditional rules (`useVueValidVIf`, `useVueValidVElse`, and `useVueValidVElseIf`) related to whitespace handling, newlines, and self-closing tags.
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ fn has_v_if_or_else_if_directives(element: &AnyHtmlElement) -> bool {
AnyVueDirective::try_cast(attribute.syntax().clone())
&& let Ok(name_token) = vue_dir.name_token()
{
let name = name_token.text();
let name = name_token.text_trimmed();
if name == "v-if" || name == "v-else-if" {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ fn has_v_if_or_else_if_directives(element: &AnyHtmlElement) -> bool {
AnyVueDirective::try_cast(attribute.syntax().clone())
&& let Ok(name_token) = vue_dir.name_token()
{
let name = name_token.text();
let name = name_token.text_trimmed();
if (name == "v-if" || name == "v-else-if") && is_valid_chain_directive(name, &vue_dir) {
return true;
}
Expand Down
52 changes: 14 additions & 38 deletions crates/biome_html_analyze/src/lint/nursery/use_vue_valid_v_if.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use biome_analyze::{
Ast, Rule, RuleDiagnostic, RuleDomain, RuleSource, context::RuleContext, declare_lint_rule,
};
use biome_console::markup;
use biome_html_syntax::{AnyVueDirective, HtmlElement, VueDirective};
use biome_html_syntax::{AnyVueDirective, HtmlAttributeList, VueDirective};
use biome_rowan::{AstNode, AstNodeList, TextRange};
use biome_rule_options::use_vue_valid_v_if::UseVueValidVIfOptions;

Expand Down Expand Up @@ -106,10 +106,7 @@ impl Rule for UseVueValidVIf {
}

// Check for conflicts with v-else or v-else-if on the same element
if let Some(element) = find_containing_element(vue_directive)
&& let Some(conflict_range) =
find_conflicting_else_directives(&element, vue_directive)
{
if let Some(conflict_range) = find_conflicting_else_directives(vue_directive) {
return Some(ViolationKind::ConflictsWithElse(conflict_range));
}

Expand Down Expand Up @@ -168,38 +165,17 @@ impl Rule for UseVueValidVIf {
}
}

/// Find containing HTML element for a Vue directive
fn find_containing_element(directive: &VueDirective) -> Option<HtmlElement> {
directive
.syntax()
.ancestors()
.skip(1)
.find_map(HtmlElement::cast)
}

/// Find conflicting v-else or v-else-if directives on the same element
fn find_conflicting_else_directives(
element: &HtmlElement,
v_if_directive: &VueDirective,
) -> Option<TextRange> {
let opening_element = element.opening_element().ok()?;

for attribute in opening_element.attributes() {
if let Some(AnyVueDirective::VueDirective(directive)) = attribute.as_any_vue_directive() {
// Skip the v-if directive we're currently checking
if directive.syntax() == v_if_directive.syntax() {
continue;
}

// Check for v-else or v-else-if
if let Ok(name_token) = directive.name_token() {
let name = name_token.text();
if name == "v-else" || name == "v-else-if" {
return Some(directive.range());
}
}
}
}

None
fn find_conflicting_else_directives(v_if: &VueDirective) -> Option<TextRange> {
v_if.syntax()
.ancestors()
.find_map(HtmlAttributeList::cast)?
.into_iter()
.find_map(|attr| {
let other = attr.as_any_vue_directive()?.as_vue_directive()?;
let name = other.name_token().ok()?;
(other.syntax() != v_if.syntax()
&& matches!(name.text_trimmed(), "v-else" | "v-else-if"))
.then(|| other.range())
})
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,20 @@
<div v-else></div>
<span v-if="cond2"></span>
<span v-else></span>

<!-- Multiline conditional elements -->
<div
v-if="condition"
data-attr1
data-attr2
data-attr3
data-attr4
data-attr5
data-attr6
/>
<div v-else></div>

<!-- Nested conditionals with self-closing tag -->
<div v-if="cond1"></div>
<div v-else><span v-if="cond2" /></div>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,21 @@ expression: valid.vue
<div v-else></div>
<span v-if="cond2"></span>
<span v-else></span>

<!-- Multiline conditional elements -->
<div
v-if="condition"
data-attr1
data-attr2
data-attr3
data-attr4
data-attr5
data-attr6
/>
<div v-else></div>

<!-- Nested conditionals with self-closing tag -->
<div v-if="cond1"></div>
<div v-else><span v-if="cond2" /></div>
</template>
```
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,20 @@
<div v-if="user.age >= 18 && user.hasPermission"></div>
<div v-else-if="user.age >= 13 && user.parentalConsent"></div>
<div v-else></div>

<!-- Multiline conditional elements -->
<div
v-if="cond1"
data-attr1
data-attr2
data-attr3
data-attr4
data-attr5
data-attr6
/>
<div v-else-if="cond2"></div>

<!-- Nested conditionals with self-closing tag -->
<div v-if="cond1"></div>
<div v-else-if="cond2"><span v-if="cond3" /></div>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -54,5 +54,21 @@ expression: valid.vue
<div v-if="user.age >= 18 && user.hasPermission"></div>
<div v-else-if="user.age >= 13 && user.parentalConsent"></div>
<div v-else></div>

<!-- Multiline conditional elements -->
<div
v-if="cond1"
data-attr1
data-attr2
data-attr3
data-attr4
data-attr5
data-attr6
/>
<div v-else-if="cond2"></div>

<!-- Nested conditionals with self-closing tag -->
<div v-if="cond1"></div>
<div v-else-if="cond2"><span v-if="cond3" /></div>
</template>
```
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@
<div v-if="a"></div>
<div v-else-if="b"></div>
<div v-else></div>
<div id="x" class="y" v-if="flag"></div>
<div id="x" class="y" v-if="flag"></div>

<!-- Nested conditionals with self-closing tag -->
<div v-if="cond1"></div>
<div v-else><span v-if="cond2"/></div>
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,8 @@ expression: valid.vue
<div v-else-if="b"></div>
<div v-else></div>
<div id="x" class="y" v-if="flag"></div>

<!-- Nested conditionals with self-closing tag -->
<div v-if="cond1"></div>
<div v-else><span v-if="cond2"/></div>
```
Loading