fix(linter): handle destructuring from this in noUnusedPrivateClassMembers#9047
fix(linter): handle destructuring from this in noUnusedPrivateClassMembers#9047solssak wants to merge 1 commit intobiomejs:mainfrom
this in noUnusedPrivateClassMembers#9047Conversation
🦋 Changeset detectedLatest commit: 8172a55 The changes in this PR will be included in the next version bump. This PR includes changesets to release 13 packages
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 |
|
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:
WalkthroughThis PR updates the no_unused_private_class_members lint to recognise private class members accessed via object destructuring from Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts (beta)
No actionable comments were generated in the recent review. 🎉 🧹 Recent nitpick comments
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @.changeset/fix-hr-presentation-role.md:
- Around line 1-5: The changeset .changeset/fix-hr-presentation-role.md only
documents the fix for `#9024`; you must add a separate changeset for the other fix
(issue `#9008`) that describes the bugfix for destructuring from this in the
noUnusedPrivateClassMembers rule. Create a new changeset file (matching the
repo's changeset format) that starts with "Fixed [`#9008`](issue link): ..." and
explains that destructuring assignments from this in noUnusedPrivateClassMembers
are now handled correctly, referencing the noUnusedPrivateClassMembers rule name
so the change is discoverable.
🧹 Nitpick comments (3)
crates/biome_js_analyze/src/lint/correctness/no_unused_private_class_members.rs (3)
461-465: Simplify nestedif let/Okhandling.The double unwrap via
mapthenif let Okis a bit convoluted. Consider flattening withand_then.♻️ Minor cleanup
- if let Some(name) = shorthand.identifier().ok().map(|id| id.name_token()) { - if let Ok(token) = name { - names.push(token.text_trimmed().to_string()); - } - } + if let Some(token) = shorthand + .identifier() + .ok() + .and_then(|id| id.name_token().ok()) + { + names.push(token.text_trimmed().to_string()); + }Based on learnings: "Use functional methods like
map,filter, andand_thenonResultandOptiontypes instead of nestedif letstatements to avoid excessive indentation."
634-667:member_namelargely duplicatesmatch_js_nameandproperty_range.All three methods walk the same match arms to extract member names. Consider having
member_namebe the single source of truth, then expressingmatch_js_nameasself.member_name().map(|n| n == token). This would deduplicate ~40 lines and reduce the maintenance surface.Not blocking — happy to defer this to a follow-up.
400-486:get_destructured_names_from_thisis called on every non-AnyJsNamedescendant node.Each call attempts two
cast_refoperations. In practice this is cheap (just a kind check), but you could short-circuit with a kind check before entering the function. Very minor — not blocking.One edge case worth noting: computed property keys in destructuring (e.g.,
const { [expr]: val } = this) won't be caught sinceas_js_literal_member_name()returnsNone. This is acceptable — it mirrors the existing caveat for computed access already documented in the rule — but consider adding a comment for posterity.
| --- | ||
| "@biomejs/biome": patch | ||
| --- | ||
|
|
||
| Fixed [#9024](https://github.com/biomejs/biome/issues/9024). The `noInteractiveElementToNoninteractiveRole` rule no longer incorrectly flags `<hr>` elements with `role="presentation"` or `role="none"`. The `separator` role (implicit role of `<hr>`) is now treated as non-interactive, matching the WAI-ARIA spec where a non-focusable separator is a static structural element. |
There was a problem hiding this comment.
Missing changeset for issue #9008?
This changeset covers the <hr> separator fix (#9024), but the PR also fixes #9008 (destructuring from this in noUnusedPrivateClassMembers). There doesn't appear to be a changeset for that second fix. Based on learnings, bug fixes should have a changeset starting with Fixed [#NUMBER](issue link): ....
🤖 Prompt for AI Agents
In @.changeset/fix-hr-presentation-role.md around lines 1 - 5, The changeset
.changeset/fix-hr-presentation-role.md only documents the fix for `#9024`; you
must add a separate changeset for the other fix (issue `#9008`) that describes the
bugfix for destructuring from this in the noUnusedPrivateClassMembers rule.
Create a new changeset file (matching the repo's changeset format) that starts
with "Fixed [`#9008`](issue link): ..." and explains that destructuring
assignments from this in noUnusedPrivateClassMembers are now handled correctly,
referencing the noUnusedPrivateClassMembers rule name so the change is
discoverable.
There was a problem hiding this comment.
The changeset for #9008 already exists at .changeset/fix-unused-private-destructuring.md. The fix-hr-presentation-role.md file is from a separate commit on main, not part of this PR's changes.
There was a problem hiding this comment.
This diff shouldn't be here at all. The PR for this changeset hasn't even been merged at all, and it doesn't even exist yet in the PR that it should be in.
There was a problem hiding this comment.
@dyc3
Thanks for catching this. The branch was created from a wrong base that included an unrelated commit, so it leaked into this PR's diff. I've rebased to remove it — now only the destructuring fix remains.
810b290 to
d3ade0a
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
d3ade0a to
a9a58a5
Compare
ematipico
left a comment
There was a problem hiding this comment.
Thank you. The implementation is a bit wasteful, I highlighted the changes that are needed
| .ok() | ||
| .and_then(|id| id.as_js_identifier_binding()?.name_token().ok()) | ||
| { | ||
| names.push(name.text_trimmed().to_string()); |
There was a problem hiding this comment.
Don't use to_string because it allocates a string. Use token_text. There's a method that returns TokenText
There was a problem hiding this comment.
Thanks for the suggestion! Updated to use token_text_trimmed() for token-based names and kept name().ok() as-is for JsLiteralMemberName since it already returns TokenText. No more unnecessary allocations.
| } | ||
| } | ||
|
|
||
| fn member_name(&self) -> Option<String> { |
There was a problem hiding this comment.
Don't return a String. Return a JsSyntaxToken or a TokenText
There was a problem hiding this comment.
Good call. Changed the return type to Option. For the class member branches, I'm using Into from ClassMemberName, and token_text_trimmed() for the TsPropertyParameter branch.
f89586e to
6b2f385
Compare
6b2f385 to
8172a55
Compare
Summary
Fixed #9008.
The
noUnusedPrivateClassMembersrule reported false positives when TypeScriptprivateclass members were accessed via object destructuring fromthis.Root Cause
traverse_members_usageonly matchedAnyJsNamenodes (used in direct member access likethis.myVar). In destructuring patterns likeconst { myVar } = this, the property name appears as aJsIdentifierBindinginside aJsObjectBindingPatternShorthandProperty, which is not anAnyJsNamenode and was therefore never recognized as usage.Changes
get_destructured_names_from_this()to extract property names from object destructuring patterns where the initializer isthis. Handles:const { myVar } = this;(shorthand binding pattern)const { myVar: renamed } = this;(renamed binding pattern)({ myVar } = this)(assignment destructuring pattern)AnyMember::member_name()to extract the private member name as aStringfor comparison with destructured names.traverse_members_usage.Test Plan
Added
valid.tstest file covering all destructuring patterns:DestructuringShorthand—const { myVar } = this;DestructuringMultiple— multiple private members, some accessed via destructuringDestructuringRenamed—const { myVar: renamed } = this;DestructuringAssignmentPattern—({ myVar } = this);All 7 existing tests pass. New test passes with no diagnostics.
AI Assistance Disclosure
This PR was written primarily by Claude Code.