Skip to content

fix(eslint-plugin-query): use Object.hasOwn to avoid Object.prototype false positives in no-unstable-deps - #11125

Open
mixelburg wants to merge 2 commits into
TanStack:mainfrom
mixelburg:fix/no-unstable-deps-prototype-pollution
Open

fix(eslint-plugin-query): use Object.hasOwn to avoid Object.prototype false positives in no-unstable-deps#11125
mixelburg wants to merge 2 commits into
TanStack:mainfrom
mixelburg:fix/no-unstable-deps-prototype-pollution

Conversation

@mixelburg

@mixelburg mixelburg commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

The trackedVariables record lookup in the no-unstable-deps rule used bracket access (trackedVariables[name] !== undefined) which matches inherited Object.prototype properties like toString, constructor, and valueOf. This caused false positives when those names appeared in dependency arrays alongside TanStack Query hooks.

Fixes #11118

Summary by CodeRabbit

  • Bug Fixes
    • Improved dependency validation in the ESLint rule, including identifiers that match built-in object property names such as toString.
    • Improved handling of combine properties in useQueries, including quoted property names and computed properties.
    • Updated dependency checks for more reliable query callback validation.
  • Tests
    • Added coverage for local built-in-style identifiers and combine property edge cases.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: af883c2f-94e9-4675-9f3b-b69c9b87858f

📥 Commits

Reviewing files that changed from the base of the PR and between adf4299 and 850db9b.

📒 Files selected for processing (2)
  • packages/eslint-plugin-query/src/__tests__/no-unstable-deps.test.ts
  • packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts

📝 Walkthrough

Walkthrough

The no-unstable-deps rule now tracks query hook results and validates dependency arrays during AST traversal. It removes deferred custom-hook processing and array-pattern tracking. Tests cover combine property forms and local toString names.

Changes

Unstable dependency tracking

Layer / File(s) Summary
Direct query-result tracking
packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts
Removes deferred custom-hook state, tracks direct identifier bindings from imported query hook calls, and skips useQueries calls with non-computed combine properties.
Immediate dependency validation
packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts
Checks dependency identifiers during CallExpression traversal with own-property detection.
Regression coverage
packages/eslint-plugin-query/src/__tests__/no-unstable-deps.test.ts
Adds valid cases for quoted combine properties and local toString dependencies, plus an invalid case for computed [key] properties.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant VariableDeclarator
  participant QueryHookCall
  participant TrackedVariables
  participant ReactHookCall
  participant DependencyArray
  VariableDeclarator->>QueryHookCall: inspect imported query hook call
  QueryHookCall->>TrackedVariables: record direct identifier binding
  ReactHookCall->>DependencyArray: provide dependency identifiers
  DependencyArray->>TrackedVariables: check own tracked names
  TrackedVariables-->>ReactHookCall: report unstable dependencies
Loading

Possibly related PRs

  • TanStack/query#11117: Updates the same rule to avoid inherited Object.prototype false positives and adds related tests.
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the bug and fix but omits the required Changes, Checklist, and Release Impact sections. Add the required template sections and record the local test and changeset or dev-only release-impact status.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary fix: preventing Object.prototype false positives in no-unstable-deps.
Linked Issues check ✅ Passed The changes add own-property checks and regression tests that prevent inherited Object.prototype names from being treated as tracked hooks.
Out of Scope Changes check ✅ Passed The combine-property handling and related refactoring remain within the no-unstable-deps rule objectives.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

… false positives in no-unstable-deps

The trackedVariables record lookup used bracket access which matches
inherited Object.prototype properties (toString, constructor, etc.),
causing false positives when those names appear in dependency arrays.
Use Object.hasOwn for a safe own-property check instead.
@mixelburg
mixelburg force-pushed the fix/no-unstable-deps-prototype-pollution branch from 0480692 to adf4299 Compare July 27, 2026 00:21
@mixelburg

Copy link
Copy Markdown
Contributor Author

Rebased on latest main ✅ — merge conflict resolved.

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts (1)

79-84: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make combine detection match the actual property key.

This misses useQueries({ 'combine': fn }) because non-computed quoted keys are AST Literal nodes, and false-positive it when a computed key named combine is present because { [combine]: fn } has prop.key.name === 'combine'. Add !prop.computed and include string-literal keys for "combine".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts`
around lines 79 - 84, Update the combine-property detection in the
firstArg.properties check to require !prop.computed, while matching both
identifier keys and non-computed string-literal keys whose value is "combine";
preserve the existing Property filtering and avoid treating computed keys such
as {[combine]: fn} as matches.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts`:
- Around line 79-84: Update the combine-property detection in the
firstArg.properties check to require !prop.computed, while matching both
identifier keys and non-computed string-literal keys whose value is "combine";
preserve the existing Property filtering and avoid treating computed keys such
as {[combine]: fn} as matches.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f9b8f54c-3a40-4735-9e90-c3fe50849dea

📥 Commits

Reviewing files that changed from the base of the PR and between 0480692 and adf4299.

📒 Files selected for processing (2)
  • packages/eslint-plugin-query/src/__tests__/no-unstable-deps.test.ts
  • packages/eslint-plugin-query/src/rules/no-unstable-deps/no-unstable-deps.rule.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/eslint-plugin-query/src/tests/no-unstable-deps.test.ts

@kprakhar

Copy link
Copy Markdown

Thanks for working on this! I also opened a PR addressing this issue earlier: #11117

… false positives in no-unstable-deps

- Add !prop.computed check to avoid matching {[combine]: fn} computed keys
- Support Literal key type for {'combine': fn} quoted string keys
- Previously only matched unquoted Identifier keys like {combine: fn}
@mixelburg

Copy link
Copy Markdown
Contributor Author

Fixed the combine detection per CodeRabbit review:

  • Added !prop.computed to avoid matching {[combine]: fn} computed keys as combine properties
  • Added support for Literal key type so {"combine": fn} quoted string keys are recognized
  • Previously only matched unquoted Identifier keys like {combine: fn}

The hasCombineProperty helper now correctly handles all three key forms.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

eslint-plugin-query: no-unstable-deps incorrectly treats inherited Object.prototype properties as tracked custom hooks

2 participants