Skip to content

Fixed invalid document#8437#8729

Closed
jwrhw7tueydwtt7575g wants to merge 2 commits intobiomejs:mainfrom
jwrhw7tueydwtt7575g:fixed-invalid-document
Closed

Fixed invalid document#8437#8729
jwrhw7tueydwtt7575g wants to merge 2 commits intobiomejs:mainfrom
jwrhw7tueydwtt7575g:fixed-invalid-document

Conversation

@jwrhw7tueydwtt7575g
Copy link

Fix HTML Formatter Fill/Indent Tag Mismatch Bug

Problem

When formatting HTML files containing Angular control flow syntax (@if, @switch, @case), Biome's HTML formatter throws an error: "Expected end tag of kind Fill but found Indent". This indicates a mismatch in the formatter's internal document structure where a StartFill tag is opened but an EndIndent tag is encountered before the matching EndFill.

Root Cause Analysis

The issue is in crates/biome_html_formatter/src/html/lists/element_list.rs, specifically in the FormatMultilineChildren::fmt method (lines 843-900). When using MultilineLayout::Fill, the formatter writes:

  • StartFill tag
  • Interned elements (which may contain nested Indent tags)
  • EndFill tag

The problem occurs when the interned elements contain Indent tags that get closed before the Fill tag is closed, causing a tag stack mismatch.

@changeset-bot
Copy link

changeset-bot bot commented Jan 11, 2026

⚠️ No Changeset found

Latest commit: 7609e8b

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@github-actions github-actions bot added A-Linter Area: linter A-Formatter Area: formatter L-JavaScript Language: JavaScript and super languages L-HTML Language: HTML and super languages labels Jan 11, 2026
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 11, 2026

Walkthrough

This PR encompasses improvements across HTML and JavaScript components. The HTML formatter refactors multiline element list formatting to differentiate between root and non-root nodes, adjusting how Fill and NoFill layouts are emitted. A new Angular HTML template test case with control-flow bindings is introduced. The JavaScript linter adds a guard to restrict JSX-key-in-iterable checks to JSX contexts only, and accompanying test files are updated to move non-JSX cases to valid test scenarios.

Possibly related PRs

Suggested labels

A-Formatter, L-HTML, A-Linter, L-JavaScript

Suggested reviewers

  • ematipico
  • dyc3
🚥 Pre-merge checks | ✅ 1 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is vague and unhelpfully brief, referring only to a ticket number without describing the actual changes or fix. Use a more descriptive title like 'Fix HTML formatter Fill/Indent tag mismatch in multiline children' to clearly indicate what was fixed.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description thoroughly explains the bug, root cause, and affected code, clearly relating to the changeset's formatting fixes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs:
- Around line 130-135: The check using node.parent::<JsxExpressionChild>() only
inspects the immediate parent and misses cases like parenthesised arrays (e.g.,
JsParenthesizedExpression) inside JSX; change the logic that sets is_inside_jsx
to walk ancestors instead (use node.ancestors() and detect any
JsxExpressionChild ancestor) so arrays wrapped in parentheses are correctly
recognized as being inside JSX; update the code around the is_inside_jsx
computation in use_jsx_key_in_iterable.rs to use an ancestors() search for
JsxExpressionChild rather than parent::<JsxExpressionChild>().
🧹 Nitpick comments (1)
crates/biome_html_formatter/src/html/lists/element_list.rs (1)

879-970: Non-root Fill fix is solid; a small simplification would reduce moving parts.

The “Fill tags outside, block_indent inside” approach is exactly what the bug description calls for. The only nit: the elements_format closure is a bit ceremony-heavy—if there’s a helper in the formatter to indent/write an interned element directly, using it would make this harder to break later.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95aba98 and 7609e8b.

📒 Files selected for processing (5)
  • crates/biome_html_formatter/src/html/lists/element_list.rs
  • crates/biome_html_formatter/tests/specs/prettier/html/angular-control-flow.html
  • crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs
  • crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/invalid.jsx
  • crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/valid.jsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (CONTRIBUTING.md)

**/*.rs: Use inline rustdoc documentation for rules, assists, and their options
Use the dbg!() macro for debugging output in Rust tests and code
Use doc tests (doctest) format with code blocks in rustdoc comments; ensure assertions pass in tests

Files:

  • crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs
  • crates/biome_html_formatter/src/html/lists/element_list.rs
🧠 Learnings (16)
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use helper functions like `map`, `filter`, and `and_then` to avoid excessive nested `if let` statements

Applied to files:

  • crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs
📚 Learning: 2025-12-22T09:26:56.943Z
Learnt from: ematipico
Repo: biomejs/biome PR: 8537
File: crates/biome_js_analyze/src/lint/nursery/no_leaked_render.rs:167-210
Timestamp: 2025-12-22T09:26:56.943Z
Learning: When defining lint rules (declare_lint_rule!), only specify fix_kind if the rule implements an action(...) function. Rules that only emit diagnostics without a code fix should omit fix_kind. This applies to all Rust lint rule definitions under crates/.../src/lint (e.g., crates/biome_js_analyze/src/lint/...).

Applied to files:

  • crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Prefer using `Box<[_]>` over `Vec<_>` for signal collections to reduce memory usage

Applied to files:

  • crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `declare_node_union!` macro to query multiple node types together to avoid redundant traversal passes

Applied to files:

  • crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs
  • crates/biome_html_formatter/src/html/lists/element_list.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/*_analyze/**/src/lint/**/*.rs : Use `.ok()?` to transform `Result` types into `Option` or `let else` pattern to handle errors when the function returns `Vec`

Applied to files:

  • crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs
📚 Learning: 2025-11-24T18:05:42.356Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_type_info/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:42.356Z
Learning: Applies to crates/biome_js_type_info/**/*.rs : Store type data in linear vectors instead of using recursive data structures with `Arc` for improved data locality and performance

Applied to files:

  • crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs
📚 Learning: 2026-01-02T14:58:16.536Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_analyze/CONTRIBUTING.md:0-0
Timestamp: 2026-01-02T14:58:16.536Z
Learning: Applies to crates/biome_analyze/**/tests/specs/**/* : Create test files with `invalid` and `valid` prefixes to represent code that should and should not trigger the rule

Applied to files:

  • crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/invalid.jsx
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/src/lib.rs : Expose a public `format_node` function that accepts formatting options and a root syntax node, returning a `FormatResult<Formatted<Context>>` with appropriate documentation

Applied to files:

  • crates/biome_html_formatter/src/html/lists/element_list.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : Import the `FormatNode` trait and implement it for your Node when creating formatters in biome_js_formatter

Applied to files:

  • crates/biome_html_formatter/src/html/lists/element_list.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/src/**/*.rs : Use `ParseSeparatedList` and `ParseNodeList` for parsing lists with error recovery to avoid infinite loops

Applied to files:

  • crates/biome_html_formatter/src/html/lists/element_list.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Applies to crates/biome_formatter/**/biome_*_formatter/src/context.rs : Define `<Language>FormatContext` struct in a `context.rs` file containing `comments` and `source_map` fields, implementing `FormatContext` and `CstFormatContext` traits

Applied to files:

  • crates/biome_html_formatter/src/html/lists/element_list.rs
📚 Learning: 2025-11-24T18:06:03.545Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_parser/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:06:03.545Z
Learning: Applies to crates/biome_parser/**/*.ungram : Nodes that represent a list must end with the postfix `List`, e.g., `HtmlAttributeList`, and lists are mandatory (not optional) but empty by default

Applied to files:

  • crates/biome_html_formatter/src/html/lists/element_list.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: Applies to crates/biome_js_formatter/**/*.rs : When formatting AST nodes, use mandatory tokens from the AST instead of hardcoding token strings (e.g., use `node.l_paren_token().format()` instead of `token("(")`)

Applied to files:

  • crates/biome_html_formatter/src/html/lists/element_list.rs
📚 Learning: 2025-11-24T18:05:27.810Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_js_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:27.810Z
Learning: The formatter foundation relies on using the generic `Format` trait and `FormatNode` for nodes, with creation of an intermediate IR via a series of helpers

Applied to files:

  • crates/biome_html_formatter/src/html/lists/element_list.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Define `FormatHtmlSyntaxNode` struct in a `cst.rs` file implementing `FormatRule<HtmlSyntaxNode>`, `AsFormat<HtmlFormatContext>`, and `IntoFormat<HtmlFormatContext>` traits using the provided boilerplate code

Applied to files:

  • crates/biome_html_formatter/src/html/lists/element_list.rs
📚 Learning: 2025-11-24T18:05:20.371Z
Learnt from: CR
Repo: biomejs/biome PR: 0
File: crates/biome_formatter/CONTRIBUTING.md:0-0
Timestamp: 2025-11-24T18:05:20.371Z
Learning: Implement the `FormatNodeRule<N>` trait with `fmt_fields` as the only required method; default implementations of `fmt`, `is_suppressed`, `fmt_leading_comments`, `fmt_dangling_comments`, and `fmt_trailing_comments` are provided

Applied to files:

  • crates/biome_html_formatter/src/html/lists/element_list.rs
🧬 Code graph analysis (1)
crates/biome_html_formatter/src/html/lists/element_list.rs (1)
crates/biome_formatter/src/builders.rs (3)
  • format_once (2381-2389)
  • format_with (2304-2312)
  • block_indent (1189-1194)
🔇 Additional comments (4)
crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/valid.jsx (1)

111-129: Test additions align with the new “only warn in JSX-render context” behaviour.

These cases clearly lock in the intended regression fix (no diagnostics for top-level JSX arrays). Nice.

crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/invalid.jsx (1)

19-21: Spec note is clear and helps future readers.

crates/biome_html_formatter/tests/specs/prettier/html/angular-control-flow.html (1)

1-48: Great regression target; please confirm the fixture is intentionally valid (and minimal enough).

This is exactly the sort of gnarly input that flushes out tag-stack issues—just make sure the braces/control-flow blocks are balanced and that this file actually triggered the original formatter panic before the fix (so we don’t end up testing “random template noise” forever).

crates/biome_html_formatter/src/html/lists/element_list.rs (1)

845-877: Root special-casing may still risk Fill/Indent tag mismatch without validation.

Root Fill bypasses block_indent wrapping that non-root uses explicitly to prevent nested Indent tag mismatches. Whilst root-level elements shouldn't require indentation, there's no code documentation confirming this invariant, and no regression test for root Fill with nested indent-producing content. If interned root elements can emit Indent tags at all, you'd reintroduce the original mismatch.

Either add a targeted test for root multiline Fill with nested indentation, or document why root elements provably cannot generate nested Indent tags.

Comment on lines 130 to +135
let is_inside_jsx = node.parent::<JsxExpressionChild>().is_some();
// Only check for keys when the array is inside JSX context (used for rendering)
// Arrays outside JSX context (e.g., const arr = [<Hello />]) don't need keys
if !is_inside_jsx {
return vec![];
}
Copy link
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:

# First, find the biome_rowan crate and understand how parent::<T>() works
fd -t f "rowan" --type d | head -5

Repository: biomejs/biome

Length of output: 76


🏁 Script executed:

# Search for parent method definition in the codebase
rg -t rs "fn parent" --max-count 20 | grep -E "(pub|fn)\s+parent"

Repository: biomejs/biome

Length of output: 83


🏁 Script executed:

# Look at the test cases in the file to see what's covered
cat -n crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs | head -200

Repository: biomejs/biome

Length of output: 7995


🏁 Script executed:

# Find the AstNode trait definition in biome_rowan
fd -path "*/biome_rowan/*" -type f -name "*.rs" | xargs rg -l "fn parent"

Repository: biomejs/biome

Length of output: 1115


🏁 Script executed:

# Search for parent method signature specifically
rg "fn parent" crates/biome_rowan/ -A 2

Repository: biomejs/biome

Length of output: 2064


🏁 Script executed:

# Check if there are tests in the use_jsx_key_in_iterable file that cover wrapped arrays
tail -n +200 crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs | head -300

Repository: biomejs/biome

Length of output: 10131


🏁 Script executed:

# Look for test cases in the file
tail -n +500 crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs | head -500

Repository: biomejs/biome

Length of output: 974


🏁 Script executed:

# Check the AstNode trait definition in biome_rowan/src/ast/mod.rs
sed -n '1,50p' crates/biome_rowan/src/ast/mod.rs

Repository: biomejs/biome

Length of output: 1842


🏁 Script executed:

# Search for the unwrap_parenthesis function to understand how parentheses are handled elsewhere
rg "fn unwrap_parenthesis" crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs -A 5

Repository: biomejs/biome

Length of output: 340


🏁 Script executed:

# Search for test cases at the end of the file
tail -n +850 crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Look at the AstNode trait's parent method more carefully - check if there's an ancestors method
rg "fn ancestors" crates/biome_rowan/src/ast/mod.rs -A 3

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Check if SyntaxNode has an ancestors method
rg "fn ancestors" crates/biome_rowan/src/syntax/node.rs -A 3

Repository: biomejs/biome

Length of output: 177


🏁 Script executed:

# Get test cases at the end of the file
wc -l crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs

Repository: biomejs/biome

Length of output: 132


🏁 Script executed:

# Get the test section
tail -n 200 crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs

Repository: biomejs/biome

Length of output: 6216


🏁 Script executed:

# Get the full test section at the end of the file
tail -n +330 crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs

Repository: biomejs/biome

Length of output: 6156


🏁 Script executed:

# Check line 11 to confirm JsxExpressionChild is imported correctly
sed -n '1,15p' crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs

Repository: biomejs/biome

Length of output: 873


🏁 Script executed:

# Find test cases for this rule
rg "use_jsx_key_in_iterable" --type f --include="*.rs" | grep -i test

Repository: biomejs/biome

Length of output: 498


🏁 Script executed:

# Look at the test file
fd "use_jsx_key_in_iterable" -path "*test*" -o -path "*tests*" | head -5

Repository: biomejs/biome

Length of output: 225


🏁 Script executed:

# Search for test cases in the codebase
rg "use_jsx_key_in_iterable" | grep -i "test\|check"

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Look for test directories related to lints
find crates/biome_js_analyze -type d -name "*test*" -o -name "*tests*"

Repository: biomejs/biome

Length of output: 351


🏁 Script executed:

# Check if tests are in the same file or a separate directory
ls -la crates/biome_js_analyze/src/lint/correctness/

Repository: biomejs/biome

Length of output: 4396


🏁 Script executed:

# Search for test specifications or snapshots
find crates/biome_js_analyze/tests -type f -name "*.json" | xargs grep -l "use_jsx_key_in_iterable" 2>/dev/null | head -5

Repository: biomejs/biome

Length of output: 39


🏁 Script executed:

# Look for how rules are tested
ls -la crates/biome_js_analyze/tests/

Repository: biomejs/biome

Length of output: 546


🏁 Script executed:

# Check the spec_tests.rs file
head -50 crates/biome_js_analyze/tests/spec_tests.rs

Repository: biomejs/biome

Length of output: 2132


🏁 Script executed:

# Find test specifications for use_jsx_key_in_iterable
find crates/biome_js_analyze/tests/specs -type f | xargs grep -l "use_jsx_key_in_iterable" 2>/dev/null

Repository: biomejs/biome

Length of output: 41


🏁 Script executed:

# Look for jsx-key or similar test files
ls -la crates/biome_js_analyze/tests/specs/*/

Repository: biomejs/biome

Length of output: 26782


🏁 Script executed:

# Search for test files related to JSX keys
find crates/biome_js_analyze/tests/specs -type f -name "*jsx*key*" -o -name "*key*"

Repository: biomejs/biome

Length of output: 231


🏁 Script executed:

# List test files for useJsxKeyInIterable
ls -la crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/

Repository: biomejs/biome

Length of output: 660


🏁 Script executed:

# Check one of the test files to understand the format
head -100 crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/invalid.jsx

Repository: biomejs/biome

Length of output: 2006


🏁 Script executed:

# Check the valid.jsx test file
cat -n crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/valid.jsx

Repository: biomejs/biome

Length of output: 5522


🏁 Script executed:

# Now let me check the AstNode implementation more carefully - search for how parent::<T>() is defined
cat -n crates/biome_rowan/src/ast/mod.rs | sed -n '1,100p'

Repository: biomejs/biome

Length of output: 4311


🏁 Script executed:

# Search for the actual parent::<T> method implementation in the AstNode trait
rg "fn parent" crates/biome_rowan/src/ast/mod.rs -A 5

Repository: biomejs/biome

Length of output: 366


🏁 Script executed:

# Search for uses of .ancestors() in the js_analyze crate to see if there's a pattern for this
rg "\.ancestors\(" crates/biome_js_analyze/src/lint/ | head -10

Repository: biomejs/biome

Length of output: 1133


🏁 Script executed:

# Check if there's a test for parenthesized array in JSX expression
rg "\{\(\[" crates/biome_js_analyze/tests/specs/correctness/useJsxKeyInIterable/

Repository: biomejs/biome

Length of output: 39


Parenthesised arrays inside JSX won't be checked for keys.

node.parent::<JsxExpressionChild>() checks immediate parent only. For {([<Hello />])}, the array's parent is JsParenthesizedExpression, not JsxExpressionChild, so the rule skips the check. Use .ancestors() instead to walk up the tree. This pattern is already used elsewhere in the analyser for similar cases.

Suggested fix
-    let is_inside_jsx = node.parent::<JsxExpressionChild>().is_some();
+    let is_inside_jsx = node
+        .syntax()
+        .ancestors()
+        .any(|ancestor| JsxExpressionChild::can_cast(ancestor.kind()));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let is_inside_jsx = node.parent::<JsxExpressionChild>().is_some();
// Only check for keys when the array is inside JSX context (used for rendering)
// Arrays outside JSX context (e.g., const arr = [<Hello />]) don't need keys
if !is_inside_jsx {
return vec![];
}
let is_inside_jsx = node
.syntax()
.ancestors()
.any(|ancestor| JsxExpressionChild::can_cast(ancestor.kind()));
// Only check for keys when the array is inside JSX context (used for rendering)
// Arrays outside JSX context (e.g., const arr = [<Hello />]) don't need keys
if !is_inside_jsx {
return vec![];
}
🤖 Prompt for AI Agents
In @crates/biome_js_analyze/src/lint/correctness/use_jsx_key_in_iterable.rs
around lines 130 - 135, The check using node.parent::<JsxExpressionChild>() only
inspects the immediate parent and misses cases like parenthesised arrays (e.g.,
JsParenthesizedExpression) inside JSX; change the logic that sets is_inside_jsx
to walk ancestors instead (use node.ancestors() and detect any
JsxExpressionChild ancestor) so arrays wrapped in parentheses are correctly
recognized as being inside JSX; update the code around the is_inside_jsx
computation in use_jsx_key_in_iterable.rs to use an ancestors() search for
JsxExpressionChild rather than parent::<JsxExpressionChild>().

@ematipico
Copy link
Member

We don't support angular right now. Plus, this is pure AI slop.

@ematipico ematipico closed this Jan 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Formatter Area: formatter A-Linter Area: linter L-HTML Language: HTML and super languages L-JavaScript Language: JavaScript and super languages

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants