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-directive-expression-parsing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@biomejs/biome": patch
---

Fixed a bug where Vue directive attribute values like `v-bind:class="{'dynamic': true}"` were incorrectly parsed as JavaScript statements instead of expressions. Object literals inside directive values like `:class`, `v-if`, and `v-html` are now correctly parsed as expressions, preventing spurious parse errors.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
22 changes: 8 additions & 14 deletions crates/biome_html_analyze/tests/spec_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use biome_html_parser::parse_html;
use biome_html_syntax::{HtmlFileSource, HtmlLanguage};
use biome_rowan::AstNode;
use biome_test_utils::{
CheckActionType, assert_diagnostics_expectation_comment, assert_errors_are_absent,
code_fix_to_string, create_analyzer_options, diagnostic_to_string,
CheckActionType, analyze_with_workspace, assert_diagnostics_expectation_comment,
assert_errors_are_absent, code_fix_to_string, create_analyzer_options, diagnostic_to_string,
has_bogus_nodes_or_empty_slots, parse_test_path, register_leak_checker, scripts_from_json,
write_analyzer_snapshot,
};
Expand All @@ -22,6 +22,11 @@ fn run_test(input: &'static str, _: &str, _: &str, _: &str) {
let input_file = Utf8Path::new(input);
let file_name = input_file.file_name().unwrap();

// Skip options files — they are configuration, not test inputs
if file_name.ends_with(".options.json") {
return;
}

let (group, rule) = parse_test_path(input_file);
if rule == "specs" {
panic!("the test file must be placed in the {rule}/<group-name>/<rule-name>/ directory");
Expand Down Expand Up @@ -62,18 +67,7 @@ fn run_test(input: &'static str, _: &str, _: &str, _: &str) {
);
}
} else {
let Ok(source_type) = input_file.try_into() else {
return;
};
analyze_and_snap(
&mut snapshot,
&input_code,
source_type,
filter,
file_name,
input_file,
CheckActionType::Lint,
);
snapshot = analyze_with_workspace(input_file, input_code, group, rule);
};

insta::with_settings!({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<img alt="Picture of friend." />
<img alt="Image of friend." />
<img alt="PhOtO of friend." />
<img alt={"photo"} />
<img alt="piCTUre of friend." />
<img alt="imAGE of friend." />
<img alt="image of cool person" aria-hidden="false" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,13 @@ expression: invalid.html
<img alt="Picture of friend." />
<img alt="Image of friend." />
<img alt="PhOtO of friend." />
<img alt={"photo"} />
<img alt="piCTUre of friend." />
<img alt="imAGE of friend." />
<img alt="image of cool person" aria-hidden="false" />
<IMG alt="imAGE of friend." />

```

_Note: The parser emitted 2 diagnostics which are not shown here._

# Diagnostics
```
invalid.html:2:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Expand Down Expand Up @@ -63,7 +60,7 @@ invalid.html:4:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━
> 4 │ <img alt="Image of friend." />
│ ^^^^^^^^^^^^^^^^^^
5 │ <img alt="PhOtO of friend." />
6 │ <img alt={"photo"} />
6 │ <img alt="piCTUre of friend." />

i Screen readers announce img elements as "images", so it is not necessary to redeclare this in alternative text.

Expand All @@ -79,75 +76,75 @@ invalid.html:5:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━
4 │ <img alt="Image of friend." />
> 5 │ <img alt="PhOtO of friend." />
│ ^^^^^^^^^^^^^^^^^^
6 │ <img alt={"photo"} />
7 │ <img alt="piCTUre of friend." />
6 │ <img alt="piCTUre of friend." />
7 │ <img alt="imAGE of friend." />

i Screen readers announce img elements as "images", so it is not necessary to redeclare this in alternative text.


```

```
invalid.html:7:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.html:6:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Avoid the words "image", "picture", or "photo" in img element alt text.

4 │ <img alt="Image of friend." />
5 │ <img alt="PhOtO of friend." />
6 │ <img alt={"photo"} />
> 7 │ <img alt="piCTUre of friend." />
> 6 │ <img alt="piCTUre of friend." />
│ ^^^^^^^^^^^^^^^^^^^^
8 │ <img alt="imAGE of friend." />
9 │ <img alt="image of cool person" aria-hidden="false" />
7 │ <img alt="imAGE of friend." />
8 │ <img alt="image of cool person" aria-hidden="false" />

i Screen readers announce img elements as "images", so it is not necessary to redeclare this in alternative text.


```

```
invalid.html:8:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.html:7:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Avoid the words "image", "picture", or "photo" in img element alt text.

6 │ <img alt={"photo"} />
7 │ <img alt="piCTUre of friend." />
> 8 │ <img alt="imAGE of friend." />
│ ^^^^^^^^^^^^^^^^^^
9 │ <img alt="image of cool person" aria-hidden="false" />
10 │ <IMG alt="imAGE of friend." />
5 │ <img alt="PhOtO of friend." />
6 │ <img alt="piCTUre of friend." />
> 7 │ <img alt="imAGE of friend." />
│ ^^^^^^^^^^^^^^^^^^
8 │ <img alt="image of cool person" aria-hidden="false" />
9 │ <IMG alt="imAGE of friend." />

i Screen readers announce img elements as "images", so it is not necessary to redeclare this in alternative text.


```

```
invalid.html:9:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.html:8:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Avoid the words "image", "picture", or "photo" in img element alt text.

7 │ <img alt="piCTUre of friend." />
8 │ <img alt="imAGE of friend." />
> 9 │ <img alt="image of cool person" aria-hidden="false" />
6 │ <img alt="piCTUre of friend." />
7 │ <img alt="imAGE of friend." />
> 8 │ <img alt="image of cool person" aria-hidden="false" />
│ ^^^^^^^^^^^^^^^^^^^^^^
10 │ <IMG alt="imAGE of friend." />
11
9 │ <IMG alt="imAGE of friend." />
10

i Screen readers announce img elements as "images", so it is not necessary to redeclare this in alternative text.


```

```
invalid.html:10:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.html:9:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Avoid the words "image", "picture", or "photo" in img element alt text.

8 │ <img alt="imAGE of friend." />
9 │ <img alt="image of cool person" aria-hidden="false" />
> 10 │ <IMG alt="imAGE of friend." />
7 │ <img alt="imAGE of friend." />
8 │ <img alt="image of cool person" aria-hidden="false" />
> 9 │ <IMG alt="imAGE of friend." />
│ ^^^^^^^^^^^^^^^^^^
11
10

i Screen readers announce img elements as "images", so it is not necessary to redeclare this in alternative text.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<img alt="Picture of friend." />
<img alt="Image of friend." />
<img alt="PhOtO of friend." />
<img alt={"photo"} />
<img alt="piCTUre of friend." />
<img alt="imAGE of friend." />
<img alt="image of cool person" aria-hidden="false" />
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,18 @@ source: crates/biome_html_analyze/tests/spec_tests.rs
expression: invalid.vue
---
# Input
```html
```vue
<!-- should generate diagnostics -->
<img alt="Photo of friend." />
<img alt="Picture of friend." />
<img alt="Image of friend." />
<img alt="PhOtO of friend." />
<img alt={"photo"} />
<img alt="piCTUre of friend." />
<img alt="imAGE of friend." />
<img alt="image of cool person" aria-hidden="false" />

```

_Note: The parser emitted 2 diagnostics which are not shown here._

# Diagnostics
```
invalid.vue:2:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Expand Down Expand Up @@ -62,7 +59,7 @@ invalid.vue:4:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━
> 4 │ <img alt="Image of friend." />
│ ^^^^^^^^^^^^^^^^^^
5 │ <img alt="PhOtO of friend." />
6 │ <img alt={"photo"} />
6 │ <img alt="piCTUre of friend." />

i Screen readers announce img elements as "images", so it is not necessary to redeclare this in alternative text.

Expand All @@ -78,58 +75,58 @@ invalid.vue:5:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━
4 │ <img alt="Image of friend." />
> 5 │ <img alt="PhOtO of friend." />
│ ^^^^^^^^^^^^^^^^^^
6 │ <img alt={"photo"} />
7 │ <img alt="piCTUre of friend." />
6 │ <img alt="piCTUre of friend." />
7 │ <img alt="imAGE of friend." />

i Screen readers announce img elements as "images", so it is not necessary to redeclare this in alternative text.


```

```
invalid.vue:7:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.vue:6:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Avoid the words "image", "picture", or "photo" in img element alt text.

4 │ <img alt="Image of friend." />
5 │ <img alt="PhOtO of friend." />
6 │ <img alt={"photo"} />
> 7 │ <img alt="piCTUre of friend." />
> 6 │ <img alt="piCTUre of friend." />
│ ^^^^^^^^^^^^^^^^^^^^
8 │ <img alt="imAGE of friend." />
9 │ <img alt="image of cool person" aria-hidden="false" />
7 │ <img alt="imAGE of friend." />
8 │ <img alt="image of cool person" aria-hidden="false" />

i Screen readers announce img elements as "images", so it is not necessary to redeclare this in alternative text.


```

```
invalid.vue:8:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.vue:7:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Avoid the words "image", "picture", or "photo" in img element alt text.

6 │ <img alt={"photo"} />
7 │ <img alt="piCTUre of friend." />
> 8 │ <img alt="imAGE of friend." />
│ ^^^^^^^^^^^^^^^^^^
9 │ <img alt="image of cool person" aria-hidden="false" />
10
5 │ <img alt="PhOtO of friend." />
6 │ <img alt="piCTUre of friend." />
> 7 │ <img alt="imAGE of friend." />
│ ^^^^^^^^^^^^^^^^^^
8 │ <img alt="image of cool person" aria-hidden="false" />
9

i Screen readers announce img elements as "images", so it is not necessary to redeclare this in alternative text.


```

```
invalid.vue:9:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
invalid.vue:8:10 lint/a11y/noRedundantAlt ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Avoid the words "image", "picture", or "photo" in img element alt text.

7 │ <img alt="piCTUre of friend." />
8 │ <img alt="imAGE of friend." />
> 9 │ <img alt="image of cool person" aria-hidden="false" />
│ ^^^^^^^^^^^^^^^^^^^^^^
10
6 │ <img alt="piCTUre of friend." />
7 │ <img alt="imAGE of friend." />
> 8 │ <img alt="image of cool person" aria-hidden="false" />
│ ^^^^^^^^^^^^^^^^^^^^^^
9

i Screen readers announce img elements as "images", so it is not necessary to redeclare this in alternative text.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ source: crates/biome_html_analyze/tests/spec_tests.rs
expression: valid.vue
---
# Input
```html
```vue
<script setup>
</script><!-- should not generate diagnostics -->
<img alt="foo" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ source: crates/biome_html_analyze/tests/spec_tests.rs
expression: valid.vue
---
# Input
```html
```vue
<!-- should not generate diagnostics -->
<!-- img with dynamic :alt binding (Vue shorthand) -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
---
source: crates/biome_html_analyze/tests/spec_tests.rs
assertion_line: 83
expression: invalid.astro
---
# Input
```html
```astro
---
// Astro frontmatter
---
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
// Astro frontmatter
// should not generate diagnostics
---

<!-- Custom components should not trigger the rule -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
---
source: crates/biome_html_analyze/tests/spec_tests.rs
assertion_line: 83
expression: valid.astro
---
# Input
```html
```astro
---
// Astro frontmatter
// should not generate diagnostics
---
<!-- Custom components should not trigger the rule -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ source: crates/biome_html_analyze/tests/spec_tests.rs
expression: invalid.svelte
---
# Input
```html
```svelte
<!-- Native anchors without accessible content should trigger -->
<a></a>
<a> </a>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!-- should not generate diagnostics -->
<!-- Custom components should not trigger the rule -->
<Link></Link>
<CustomAnchor></CustomAnchor>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ source: crates/biome_html_analyze/tests/spec_tests.rs
expression: valid.svelte
---
# Input
```html
```svelte
<!-- should not generate diagnostics -->
<!-- Custom components should not trigger the rule -->
<Link></Link>
<CustomAnchor></CustomAnchor>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ source: crates/biome_html_analyze/tests/spec_tests.rs
expression: invalid.vue
---
# Input
```html
```vue
<template>
<!-- Native anchors without accessible content should trigger -->
<a></a>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<!-- should not generate diagnostics -->
<template>
<!-- Custom components should not trigger the rule -->
<Link></Link>
Expand Down
Loading
Loading