Conversation
🦋 Changeset detectedLatest commit: 8471364 The changes in this PR will be included in the next version bump. Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Merging this PR will not alter performance
Comparing Footnotes
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a nursery lint rule Suggested reviewers
🚥 Pre-merge checks | ✅ 2✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
crates/biome_rule_options/src/no_identical_test_title.rs (1)
3-6: Add a one-line rustdoc to the options typeEven an empty options struct is part of the rule surface here, so it wants a short comment to keep the docs tidy and consistent.
As per coding guidelines, "Use inline rustdoc documentation for rules, assists, and their options".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_rule_options/src/no_identical_test_title.rs` around lines 3 - 6, Add a one-line inline rustdoc comment to the NoIdenticalTestTitleOptions struct to document its purpose (e.g., "Options for the no_identical_test_title rule.") by placing a /// comment directly above the pub struct NoIdenticalTestTitleOptions {} declaration; keep it brief and follow existing docs style used for other rule option types..changeset/add-no-identical-test-title.md (1)
5-5: Trim the upstream rule references from the changesetThe behaviour description is already enough; the “porting
jest/no-identical-titleandvitest/no-identical-title” tail reads like implementation detail rather than release-note content.As per coding guidelines, "Changeset descriptions must be written for end users (explain impact and what changed), not developers (avoid implementation details)".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.changeset/add-no-identical-test-title.md at line 5, The changeset text includes upstream implementation detail ("porting `jest/no-identical-title` and `vitest/no-identical-title`") that should be removed; edit the changeset entry for nursery/noIdenticalTestTitle to keep only the user-facing behavior description ("This rule disallows using the same title for two `describe` blocks or two test cases at the same nesting level.") and remove the trailing "porting ..." clause so the description targets end users rather than developers.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/biome_js_analyze/src/frameworks/unit_tests.rs`:
- Around line 24-31: The is_describe_call function currently treats any member
call ending in "describe" as a test suite (e.g., foo.describe()), which is too
permissive; change the logic in is_describe_call to first split
callee.to_trimmed_text() into first and second segments and only accept the
second == "describe" case when the first segment is a known test root (e.g.,
"test", "it", or "describe"), i.e., return true if first is one of "describe" |
"fdescribe" | "xdescribe" OR (second == Some("describe") && first is one of the
allowed roots like "test" | "it" | "describe"); update the matching expression
in is_describe_call accordingly.
In `@crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rs`:
- Around line 219-230: The extraction currently ignores no-substitution template
literals, so update extract_call_title to also recognize template literal nodes
(e.g., match AnyJsExpression variants representing template literals with a
single quasi and no substitutions) and return their static inner text just like
JsStringLiteralExpression; locate the match in extract_call_title and add a
branch that extracts the template text (using the same inner_string_text() or
equivalent accessor) for single-quasi templates, then add a test fixture that
uses it(`same title`, ...) to ensure duplicate detection catches backtick
no-substitution templates.
---
Nitpick comments:
In @.changeset/add-no-identical-test-title.md:
- Line 5: The changeset text includes upstream implementation detail ("porting
`jest/no-identical-title` and `vitest/no-identical-title`") that should be
removed; edit the changeset entry for nursery/noIdenticalTestTitle to keep only
the user-facing behavior description ("This rule disallows using the same title
for two `describe` blocks or two test cases at the same nesting level.") and
remove the trailing "porting ..." clause so the description targets end users
rather than developers.
In `@crates/biome_rule_options/src/no_identical_test_title.rs`:
- Around line 3-6: Add a one-line inline rustdoc comment to the
NoIdenticalTestTitleOptions struct to document its purpose (e.g., "Options for
the no_identical_test_title rule.") by placing a /// comment directly above the
pub struct NoIdenticalTestTitleOptions {} declaration; keep it brief and follow
existing docs style used for other rule option types.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 44cd8fd8-0301-40b8-b9b2-e371fe57bf74
⛔ Files ignored due to path filters (4)
crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_diagnostics_categories/src/categories.rsis excluded by!**/categories.rsand included by**crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/invalid.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.js.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (8)
.changeset/add-no-identical-test-title.mdcrates/biome_js_analyze/src/frameworks/mod.rscrates/biome_js_analyze/src/frameworks/unit_tests.rscrates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rscrates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/invalid.jscrates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.jscrates/biome_rule_options/src/lib.rscrates/biome_rule_options/src/no_identical_test_title.rs
0a11e3b to
fe94218
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
crates/biome_rule_options/src/no_identical_test_title.rs (1)
3-6: Add rustdoc to the options type.Even an empty options struct lands in the generated config/schema surface, so it should say that the rule currently has no configurable options.
♻️ Suggested tweak
+/// Options for `noIdenticalTestTitle`. +/// +/// This rule currently has no configurable options. pub struct NoIdenticalTestTitleOptions {}As per coding guidelines, "Use inline rustdoc documentation for rules, assists, and their options".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_rule_options/src/no_identical_test_title.rs` around lines 3 - 6, Add inline rustdoc to the NoIdenticalTestTitleOptions type to document that this rule has no configurable options; update the doc comment immediately above the pub struct NoIdenticalTestTitleOptions {} to a concise sentence like "Options for the `no_identical_test_title` rule — this rule has no configurable options." so the generated config/schema surface clearly communicates there are no options; keep the comment as normal Rust doc (///) and place it directly above the struct definition.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/biome_js_analyze/src/frameworks/unit_tests.rs`:
- Around line 27-77: The matcher in is_describe_call currently only accepts a
bare "describe" identifier or a single static member whose right-most segment is
"describe", so chained modifier forms like describe.only, describe.skip, and
test.describe.only fall through; update is_describe_call to unwrap
AnyJsExpression::JsStaticMemberExpression chains (traverse member().object()
recursively) to find the right-most name token and accept it if the final
identifier is "describe", then allow additional member segments after that
(e.g., "only", "skip") by treating any further static-member chain as part of
the same describe scope; reference the is_describe_call function, the callee
variable, and AnyJsExpression::JsStaticMemberExpression/member/object traversal
when implementing the change, and add snapshot tests covering describe.only,
describe.skip, test.describe.only, and similar variants under
tests/specs/{group}/{rule}/ to ensure duplicates inside these modified suites
are detected.
---
Nitpick comments:
In `@crates/biome_rule_options/src/no_identical_test_title.rs`:
- Around line 3-6: Add inline rustdoc to the NoIdenticalTestTitleOptions type to
document that this rule has no configurable options; update the doc comment
immediately above the pub struct NoIdenticalTestTitleOptions {} to a concise
sentence like "Options for the `no_identical_test_title` rule — this rule has no
configurable options." so the generated config/schema surface clearly
communicates there are no options; keep the comment as normal Rust doc (///) and
place it directly above the struct definition.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 8660b115-0685-46c3-adb5-6633c5a08ffb
⛔ Files ignored due to path filters (8)
crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rsis excluded by!**/migrate/eslint_any_rule_to_biome.rsand included by**crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_configuration/src/generated/domain_selector.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_diagnostics_categories/src/categories.rsis excluded by!**/categories.rsand included by**crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/invalid.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.js.snapis excluded by!**/*.snapand included by**packages/@biomejs/backend-jsonrpc/src/workspace.tsis excluded by!**/backend-jsonrpc/src/workspace.tsand included by**packages/@biomejs/biome/configuration_schema.jsonis excluded by!**/configuration_schema.jsonand included by**
📒 Files selected for processing (8)
.changeset/add-no-identical-test-title.mdcrates/biome_js_analyze/src/frameworks/mod.rscrates/biome_js_analyze/src/frameworks/unit_tests.rscrates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rscrates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/invalid.jscrates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.jscrates/biome_rule_options/src/lib.rscrates/biome_rule_options/src/no_identical_test_title.rs
🚧 Files skipped from review as they are similar to previous changes (1)
- crates/biome_js_analyze/src/frameworks/mod.rs
| pub(crate) fn is_describe_call(call: &JsCallExpression) -> bool { | ||
| let Ok(callee) = call.callee() else { | ||
| return false; | ||
| }; | ||
| let callee = callee.omit_parentheses(); | ||
|
|
||
| match callee { | ||
| // describe(...) / fdescribe(...) / xdescribe(...) | ||
| AnyJsExpression::JsIdentifierExpression(ident) => ident | ||
| .name() | ||
| .and_then(|r| r.value_token()) | ||
| .is_ok_and(|tok| matches!(tok.text_trimmed(), "describe" | "fdescribe" | "xdescribe")), | ||
|
|
||
| // test.describe(...) / it.describe(...) / describe.each(...) etc. | ||
| AnyJsExpression::JsStaticMemberExpression(member) => { | ||
| // The right-hand member must be "describe". | ||
| let member_is_describe = member | ||
| .member() | ||
| .ok() | ||
| .and_then(|m| { | ||
| if let AnyJsName::JsName(n) = m { | ||
| Some(n) | ||
| } else { | ||
| None | ||
| } | ||
| }) | ||
| .and_then(|n| n.value_token().ok()) | ||
| .is_some_and(|tok| tok.text_trimmed() == "describe"); | ||
|
|
||
| if !member_is_describe { | ||
| return false; | ||
| } | ||
|
|
||
| // The left-hand object must be a known test root identifier. | ||
| member | ||
| .object() | ||
| .ok() | ||
| .map(|o| o.omit_parentheses()) | ||
| .and_then(|o| { | ||
| if let AnyJsExpression::JsIdentifierExpression(i) = o { | ||
| Some(i) | ||
| } else { | ||
| None | ||
| } | ||
| }) | ||
| .and_then(|i| i.name().and_then(|r| r.value_token()).ok()) | ||
| .is_some_and(|tok| matches!(tok.text_trimmed(), "test" | "it" | "describe")) | ||
| } | ||
|
|
||
| _ => false, | ||
| } |
There was a problem hiding this comment.
Recognise chained describe variants before classifying tests.
describe.only(...), describe.skip(...), and test.describe.only(...) all fall through here because the matcher only accepts bare describe(...) or a single static member whose last segment is describe. Those suites are then skipped entirely or treated as leaf tests, so duplicate titles inside them are missed. Please unwrap the static-member chain and treat modifier forms as describe scopes, then add coverage for the modifier variants.
Based on learnings, "All code changes MUST include tests - lint rules need snapshot tests in tests/specs/{group}/{rule}/, formatter changes need snapshot tests with valid/invalid cases, parser changes need test files covering valid and error cases".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/biome_js_analyze/src/frameworks/unit_tests.rs` around lines 27 - 77,
The matcher in is_describe_call currently only accepts a bare "describe"
identifier or a single static member whose right-most segment is "describe", so
chained modifier forms like describe.only, describe.skip, and test.describe.only
fall through; update is_describe_call to unwrap
AnyJsExpression::JsStaticMemberExpression chains (traverse member().object()
recursively) to find the right-most name token and accept it if the final
identifier is "describe", then allow additional member segments after that
(e.g., "only", "skip") by treating any further static-member chain as part of
the same describe scope; reference the is_describe_call function, the callee
variable, and AnyJsExpression::JsStaticMemberExpression/member/object traversal
when implementing the change, and add snapshot tests covering describe.only,
describe.skip, test.describe.only, and similar variants under
tests/specs/{group}/{rule}/ to ensure duplicates inside these modified suites
are detected.
fe94218 to
2192676
Compare
This stack of pull requests is managed by Graphite. Learn more about stacking. |
There was a problem hiding this comment.
♻️ Duplicate comments (1)
crates/biome_js_analyze/src/frameworks/unit_tests.rs (1)
27-78:⚠️ Potential issue | 🟠 MajorHandle chained
describemodifiers before classifying the call.This still only recognises bare
describe(...)or a single static member ending indescribe.describe.only(...),describe.skip(...), andtest.describe.only(...)will fall through here, so those scopes are skipped entirely or treated as leaf tests, and duplicate titles inside them get missed. Please unwrap the static-member chain and add snapshot coverage for the modifier variants while you’re there.Based on learnings, "All code changes MUST include tests - lint rules need snapshot tests in
tests/specs/{group}/{rule}/".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_js_analyze/src/frameworks/unit_tests.rs` around lines 27 - 78, is_describe_call currently only matches bare describe(...) or a single JsStaticMemberExpression ending in "describe" and thus misses chained modifiers like describe.only(...), describe.skip(...), or test.describe.only(...); update is_describe_call to walk/unwind a chain of JsStaticMemberExpression on the callee (peeling right-hand members) until you find the terminal name token and confirm that one of the identifiers in the chain is "describe" and that any preceding root object is one of the known test roots ("test", "it", "describe"); treat modifier names ("only", "skip", "each", etc.) as valid intermediate members rather than failing the match; update the logic in is_describe_call (and where it checks member().object() and member().member()) to traverse nested JsStaticMemberExpression nodes, and add snapshot tests under tests/specs/{group}/{rule}/ covering describe.only, describe.skip, describe.each, test.describe.only, and chained combinations so lint rules detect duplicates inside these modified describe blocks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@crates/biome_js_analyze/src/frameworks/unit_tests.rs`:
- Around line 27-78: is_describe_call currently only matches bare describe(...)
or a single JsStaticMemberExpression ending in "describe" and thus misses
chained modifiers like describe.only(...), describe.skip(...), or
test.describe.only(...); update is_describe_call to walk/unwind a chain of
JsStaticMemberExpression on the callee (peeling right-hand members) until you
find the terminal name token and confirm that one of the identifiers in the
chain is "describe" and that any preceding root object is one of the known test
roots ("test", "it", "describe"); treat modifier names ("only", "skip", "each",
etc.) as valid intermediate members rather than failing the match; update the
logic in is_describe_call (and where it checks member().object() and
member().member()) to traverse nested JsStaticMemberExpression nodes, and add
snapshot tests under tests/specs/{group}/{rule}/ covering describe.only,
describe.skip, describe.each, test.describe.only, and chained combinations so
lint rules detect duplicates inside these modified describe blocks.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 361946f2-0a7f-4a9c-b183-bcf890c73943
⛔ Files ignored due to path filters (8)
crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rsis excluded by!**/migrate/eslint_any_rule_to_biome.rsand included by**crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_configuration/src/generated/domain_selector.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_diagnostics_categories/src/categories.rsis excluded by!**/categories.rsand included by**crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/invalid.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.js.snapis excluded by!**/*.snapand included by**packages/@biomejs/backend-jsonrpc/src/workspace.tsis excluded by!**/backend-jsonrpc/src/workspace.tsand included by**packages/@biomejs/biome/configuration_schema.jsonis excluded by!**/configuration_schema.jsonand included by**
📒 Files selected for processing (8)
.changeset/add-no-identical-test-title.mdcrates/biome_js_analyze/src/frameworks/mod.rscrates/biome_js_analyze/src/frameworks/unit_tests.rscrates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rscrates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/invalid.jscrates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.jscrates/biome_rule_options/src/lib.rscrates/biome_rule_options/src/no_identical_test_title.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.js
- .changeset/add-no-identical-test-title.md
| declare_node_union! { | ||
| /// A node that represents a scope containing test/describe calls: | ||
| /// either the top-level module/script, or a `describe(...)` call. | ||
| pub AnyTestScope = JsModule | JsScript | JsCallExpression |
There was a problem hiding this comment.
My thought process here was that this would let us avoid traversing the syntax tree inside the rule, and let the analyzer just do the (ideally) single traversal as its querying. I suppose the rule could just query for JsStatementList instead and filter for the lists we want, but my hunch is that would activate the rule more often on average.
There was a problem hiding this comment.
My thought process here was that this would let us avoid traversing the syntax tree inside the rule
By default, the rule doesn't do it, but you can tell the rule to do it:
biome/crates/biome_analyze/src/rule.rs
Lines 1257 to 1292 in 0536fd3
There was a problem hiding this comment.
Is something like this what you had in mind? 8c1ccf4 There aren't any rules that use this feature
There was a problem hiding this comment.
It was initially added for useTemplate to not trigger the rule in nested templates. The rule changed since then. And yes, that's essentially how you would use it
a337d77 to
806a0fe
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/biome_js_analyze/src/frameworks/unit_tests.rs`:
- Around line 20-26: The docstring falsely claims support for
describe.each(...); fix by updating the matching logic used where
member_is_describe is checked so JsStaticMemberExpression callees also accept
the "each" modifier chain: treat a callee as a describe when either the property
name is "describe" OR the property name is "each" and its object is the
identifier or static member whose final property is "describe" (i.e. allow
patterns like describe.each(...) and test.describe.each(...)); update the check
in the function that uses member_is_describe to recognize this modifier chain
(or alternatively change the docstring to remove the claim if you prefer not to
implement the modifier handling).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 859a77a5-61d0-4a81-82d6-3c7f1dfb2231
⛔ Files ignored due to path filters (8)
crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rsis excluded by!**/migrate/eslint_any_rule_to_biome.rsand included by**crates/biome_configuration/src/analyzer/linter/rules.rsis excluded by!**/rules.rsand included by**crates/biome_configuration/src/generated/domain_selector.rsis excluded by!**/generated/**,!**/generated/**and included by**crates/biome_diagnostics_categories/src/categories.rsis excluded by!**/categories.rsand included by**crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/invalid.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.js.snapis excluded by!**/*.snapand included by**packages/@biomejs/backend-jsonrpc/src/workspace.tsis excluded by!**/backend-jsonrpc/src/workspace.tsand included by**packages/@biomejs/biome/configuration_schema.jsonis excluded by!**/configuration_schema.jsonand included by**
📒 Files selected for processing (8)
.changeset/add-no-identical-test-title.mdcrates/biome_js_analyze/src/frameworks/mod.rscrates/biome_js_analyze/src/frameworks/unit_tests.rscrates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rscrates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/invalid.jscrates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.jscrates/biome_rule_options/src/lib.rscrates/biome_rule_options/src/no_identical_test_title.rs
🚧 Files skipped from review as they are similar to previous changes (6)
- crates/biome_js_analyze/src/frameworks/mod.rs
- crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.js
- crates/biome_rule_options/src/no_identical_test_title.rs
- crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rs
- .changeset/add-no-identical-test-title.md
- crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/invalid.js
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rs (1)
175-209: ConsiderHashSetfor O(1) duplicate lookups.Using
Vec::containsfordescribe_titlesandtest_titlesgives O(n) per lookup, yielding O(n²) overall for scopes with many tests. For most real-world test files this is likely fine, but aHashSet<TokenText>would scale better.♻️ Suggested refactor
+use std::collections::HashSet; + fn scan_scope(statements: &[AnyJsStatement]) -> ScopeScanResult { - let mut describe_titles = vec![]; - let mut test_titles = vec![]; + let mut describe_titles: HashSet<TokenText> = HashSet::new(); + let mut test_titles: HashSet<TokenText> = HashSet::new(); let mut duplicates = vec![]; let mut suppressed_scopes = vec![]; for stmt in statements { // ... if is_describe_call(&call) { if let Some(title) = extract_call_title(&call) { - if describe_titles.contains(&title) { + if !describe_titles.insert(title) { duplicates.push(call.clone()); - } else { - describe_titles.push(title); } } // ... } else if is_unit_test(&call) && let Some(title) = extract_call_title(&call) { - if test_titles.contains(&title) { + if !test_titles.insert(title) { duplicates.push(call); - } else { - test_titles.push(title); } } } // ... }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rs` around lines 175 - 209, Replace the O(n) Vec lookups for duplicate title detection with a HashSet: change describe_titles and test_titles to HashSet<TokenText> (or the actual title type), import std::collections::HashSet, and when you extract a title in scan_scope use set.insert(title.clone()) (or check the return value) to determine if it was already present and then push the call into duplicates; remove the Vec::contains checks and the pushes that add titles to the vecs and instead insert into the corresponding HashSet; keep duplicates and suppressed_scopes as Vecs and preserve the behavior around describe_body_statements, call_from_statement, is_describe_call, is_unit_test, extract_call_title, and scan_scope while ensuring you clone or borrow titles as needed to satisfy ownership.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rs`:
- Around line 218-229: The code currently maintains a redundant suppression
mechanism (suppressed_scopes / suppressed_nodes) that hides nodes which never
produce signals because scope_statements_for_call already requires a JsScript
parent and nested describes cannot satisfy that; remove the suppressed_scopes
and suppressed_nodes data structures and all code that populates or checks them
(references to suppressed_scopes, suppressed_nodes, and any early returns or
skips based on them) and simplify the signal-generation flow to rely solely on
scope_statements_for_call (and functions it calls like module_statements) so
nodes that naturally return None are simply not signaled; ensure related tests
or comments that referenced suppression are updated or removed.
---
Nitpick comments:
In `@crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rs`:
- Around line 175-209: Replace the O(n) Vec lookups for duplicate title
detection with a HashSet: change describe_titles and test_titles to
HashSet<TokenText> (or the actual title type), import std::collections::HashSet,
and when you extract a title in scan_scope use set.insert(title.clone()) (or
check the return value) to determine if it was already present and then push the
call into duplicates; remove the Vec::contains checks and the pushes that add
titles to the vecs and instead insert into the corresponding HashSet; keep
duplicates and suppressed_scopes as Vecs and preserve the behavior around
describe_body_statements, call_from_statement, is_describe_call, is_unit_test,
extract_call_title, and scan_scope while ensuring you clone or borrow titles as
needed to satisfy ownership.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 83256805-b7a9-4f38-b7f3-6277a20bc221
⛔ Files ignored due to path filters (2)
crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/invalid.js.snapis excluded by!**/*.snapand included by**crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.js.snapis excluded by!**/*.snapand included by**
📒 Files selected for processing (3)
crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rscrates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/invalid.jscrates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.js
✅ Files skipped from review due to trivial changes (2)
- crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/invalid.js
- crates/biome_js_analyze/tests/specs/nursery/noIdenticalTestTitle/valid.js
| fn scope_statements_for_call(call: &JsCallExpression) -> Option<Vec<AnyJsStatement>> { | ||
| let expr_stmt = call.parent::<JsExpressionStatement>()?; | ||
|
|
||
| if let Some(module_items) = expr_stmt.parent::<JsModuleItemList>() { | ||
| return module_statements(&module_items); | ||
| } | ||
|
|
||
| let statement_list = expr_stmt.parent::<JsStatementList>()?; | ||
|
|
||
| statement_list.parent::<JsScript>()?; | ||
| Some(statement_list.into_iter().collect()) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify whether nested describe calls can ever satisfy scope_statements_for_call
# by checking for JsStatementList parents other than JsScript/JsModule in the codebase.
rg -n "JsStatementList" crates/biome_js_syntax/src/generated/nodes.rs | head -40Repository: biomejs/biome
Length of output: 1007
🏁 Script executed:
#!/bin/bash
# Read the file to understand the suppression mechanism and context
wc -l crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rsRepository: biomejs/biome
Length of output: 128
🏁 Script executed:
#!/bin/bash
# View the suppression mechanism at lines 133-141 and 195-199
sed -n '125,210p' crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rsRepository: biomejs/biome
Length of output: 2670
🏁 Script executed:
#!/bin/bash
# View more context around the function at lines 218-229
sed -n '210,250p' crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rsRepository: biomejs/biome
Length of output: 1283
🏁 Script executed:
#!/bin/bash
# Find where scope_statements_for_call is used
rg -n "scope_statements_for_call" crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rsRepository: biomejs/biome
Length of output: 221
🏁 Script executed:
#!/bin/bash
# Find the describe_body_statements function definition
rg -n "describe_body_statements" crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rs -A 8Repository: biomejs/biome
Length of output: 1018
🏁 Script executed:
#!/bin/bash
# View the beginning of the file to see the rule structure and entry point
head -130 crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rsRepository: biomejs/biome
Length of output: 3936
🏁 Script executed:
#!/bin/bash
# Verify JsStatementList parent possibilities in nested contexts
# Check what can be parent of JsStatementList besides JsScript
rg -n "pub.*statements.*JsStatementList" crates/biome_js_syntax/src/generated/nodes.rs | head -20Repository: biomejs/biome
Length of output: 442
🏁 Script executed:
#!/bin/bash
# Get context around JsStatementList declarations to identify parent node types
sed -n '625,650p' crates/biome_js_syntax/src/generated/nodes.rs && \
echo "---" && \
sed -n '2964,2990p' crates/biome_js_syntax/src/generated/nodes.rs && \
echo "---" && \
sed -n '5911,5940p' crates/biome_js_syntax/src/generated/nodes.rs && \
echo "---" && \
sed -n '6255,6280p' crates/biome_js_syntax/src/generated/nodes.rsRepository: biomejs/biome
Length of output: 3386
🏁 Script executed:
#!/bin/bash
# Check if there are test cases that verify nested describe handling
fd -e rs "no_identical_test_title" crates/biome_js_analyze/tests --exec head -5 {} \;Repository: biomejs/biome
Length of output: 39
🏁 Script executed:
#!/bin/bash
# Find test files for this rule
find crates -name "*no_identical_test_title*" -type fRepository: biomejs/biome
Length of output: 181
🏁 Script executed:
#!/bin/bash
# Search for any git history or comments explaining the suppression mechanism
git log --oneline -S "suppressed_scopes" -- crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rs | head -5Repository: biomejs/biome
Length of output: 107
🏁 Script executed:
#!/bin/bash
# Check if there are inline comments near the suppression code
sed -n '180,210p' crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rsRepository: biomejs/biome
Length of output: 1109
🏁 Script executed:
#!/bin/bash
# View the suppressed_nodes callback to confirm it only processes items never reached
sed -n '138,143p' crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rsRepository: biomejs/biome
Length of output: 275
🏁 Script executed:
#!/bin/bash
# Verify the parent check once more - confirm JsBlockStatement won't satisfy statement_list.parent::<JsScript>()
sed -n '218,228p' crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rsRepository: biomejs/biome
Length of output: 489
Remove the redundant suppression mechanism.
You're correct—scope_statements_for_call requires a JsScript parent, which nested describes (parented by JsFunctionBody or JsBlockStatement) can never satisfy. They naturally return None and skip signal generation entirely. The suppressed_scopes / suppressed_nodes machinery (lines 133–141, 195–199) suppresses nodes that never generate signals in the first place, making it unnecessary. Consider removing it to simplify the implementation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@crates/biome_js_analyze/src/lint/nursery/no_identical_test_title.rs` around
lines 218 - 229, The code currently maintains a redundant suppression mechanism
(suppressed_scopes / suppressed_nodes) that hides nodes which never produce
signals because scope_statements_for_call already requires a JsScript parent and
nested describes cannot satisfy that; remove the suppressed_scopes and
suppressed_nodes data structures and all code that populates or checks them
(references to suppressed_scopes, suppressed_nodes, and any early returns or
skips based on them) and simplify the signal-generation flow to rely solely on
scope_statements_for_call (and functions it calls like module_statements) so
nodes that naturally return None are simply not signaled; ensure related tests
or comments that referenced suppression are updated or removed.
This comment was marked as resolved.
This comment was marked as resolved.
8c1ccf4 to
11d89d9
Compare
ematipico
left a comment
There was a problem hiding this comment.
Looks good. Just a nit: let's docstrings the methods
8c164d1 to
aafa435
Compare
aafa435 to
8981fe2
Compare
Summary
Adds
noIdenticalTestTitleGenerated by sonnet 4.6
Test Plan
added snapshot tests
Docs