Skip to content
Closed
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
53 changes: 53 additions & 0 deletions crates/biome_cli/tests/cases/handle_astro_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ const title = "My Page";
</body>
</html>"#;

const ASTRO_FILE_USE_JSX_KEY_IN_ITERABLE: &str = r#"---
const items = ["one", "two", "three"];
---
<ul>
{items.map((item) => <li>{item}</li>)}
</ul>"#;

#[test]
fn format_astro_files() {
let fs = MemoryFileSystem::default();
Expand Down Expand Up @@ -291,6 +298,52 @@ schema + sure()
));
}

#[test]
fn use_jsx_key_in_iterable_is_ignored_for_astro_files() {
let fs = MemoryFileSystem::default();
let mut console = BufferConsole::default();

fs.insert(
"biome.json".into(),
r#"{
"linter": {
"domains": {
"react": "recommended"
}
},
"html": {
"linter": {
"enabled": true
},
"experimentalFullSupportEnabled": true
}
}"#
.as_bytes(),
);

let astro_file_path = Utf8Path::new("file.astro");
fs.insert(
astro_file_path.into(),
ASTRO_FILE_USE_JSX_KEY_IN_ITERABLE.as_bytes(),
);

let (fs, result) = run_cli(
fs,
&mut console,
Args::from(["lint", astro_file_path.as_str()].as_slice()),
);

assert!(result.is_ok(), "run_cli returned {result:?}");

assert_cli_snapshot(SnapshotPayload::new(
module_path!(),
"use_jsx_key_in_iterable_is_ignored_for_astro_files",
fs,
console,
result,
));
}

#[test]
fn lint_and_fix_astro_files() {
let fs = MemoryFileSystem::default();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
source: crates/biome_cli/tests/snap_test.rs
expression: redactor(content)
---
## `biome.json`

```json
{
"linter": {
"domains": {
"react": "recommended"
}
},
"html": {
"linter": { "enabled": true },
"experimentalFullSupportEnabled": true
}
}
```

## `file.astro`

```astro
---
const items = ["one", "two", "three"];
---
<ul>
{items.map((item) => <li>{item}</li>)}
</ul>
```

# Emitted Messages

```block
Checked 1 file in <TIME>. No fixes applied.
```
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ use biome_diagnostics::Severity;
use biome_js_semantic::SemanticModel;
use biome_js_syntax::{
AnyJsExpression, AnyJsFunctionBody, AnyJsMemberExpression, AnyJsObjectMember, AnyJsStatement,
AnyJsSwitchClause, AnyJsxAttribute, AnyJsxChild, JsArrayElementList, JsArrayExpression,
JsCallArgumentList, JsCallArguments, JsCallExpression, JsFunctionBody, JsNewExpression,
JsObjectExpression, JsStatementList, JsxAttributeList, JsxExpressionChild, JsxTagExpression,
AnyJsSwitchClause, AnyJsxAttribute, AnyJsxChild, EmbeddingKind, JsArrayElementList,
JsArrayExpression, JsCallArgumentList, JsCallArguments, JsCallExpression, JsFileSource,
JsFunctionBody, JsNewExpression, JsObjectExpression, JsStatementList, JsxAttributeList,
JsxExpressionChild, JsxTagExpression,
};
use biome_rowan::{AstNode, AstNodeList, AstSeparatedList, TextRange, declare_node_union};
use biome_rule_options::use_jsx_key_in_iterable::UseJsxKeyInIterableOptions;
Expand Down Expand Up @@ -84,6 +85,13 @@ impl Rule for UseJsxKeyInIterable {
type Options = UseJsxKeyInIterableOptions;

fn run(ctx: &RuleContext<Self>) -> Self::Signals {
if matches!(
ctx.source_type::<JsFileSource>().as_embedding_kind(),
EmbeddingKind::Astro { .. }
) {
return Vec::new().into_boxed_slice();
}
Comment on lines +88 to +93
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify embed-kind assignment paths for Astro and this rule's guard.
# Expected: Astro EmbedCandidate::Element path does not assign EmbeddingKind::Astro,
# which means the Line 89 guard won't match those embeds.

rg -n -C4 'EmbedCandidate::(Frontmatter|Element|TextExpression|Directive)|with_embedding_kind\(EmbeddingKind::Astro' crates/biome_service/src/file_handlers/html.rs

rg -n -C3 'source_type::<JsFileSource>\(\)\.as_embedding_kind\(\)|EmbeddingKind::Astro' crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs

Repository: biomejs/biome

Length of output: 7078


Astro skip guard doesn't cover <script> element embeds

The guard on line 89 only skips when as_embedding_kind() returns EmbeddingKind::Astro { .. }. However, Astro <script> element embeds (created as EmbedCandidate::Element) are deliberately assigned no embedding kind—they only skip for Frontmatter, TextExpression, and Directive contexts. If the intent is to exclude the rule entirely from Astro files, the guard is incomplete.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs`
around lines 88 - 93, The current early return checks only for
ctx.source_type::<JsFileSource>().as_embedding_kind() == EmbeddingKind::Astro,
but that misses Astro <script> element embeds which have no embedding kind;
update the guard to also detect the containing file is an Astro file and return
early (for example, check for the presence of an Astro source type like
ctx.source_type::<AstroFileSource>() or inspect the file/language kind on ctx to
identify Astro files) so that the rule is skipped for all Astro contexts
(including EmbedCandidate::Element and the Frontmatter/TextExpression/Directive
cases).


let node = ctx.query();
let model = ctx.model();
let options = ctx.options();
Expand Down
Loading