Skip to content

Conversation

mdmower-csnw
Copy link
Contributor

@mdmower-csnw mdmower-csnw commented Sep 27, 2025

🎯 Changes

Use TypeScript's satisfies operator to verify that the shape of plugins matches ESLint.Plugin (the extended version of it) while retaining its actual shape.

Fixes #9689

βœ… Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm test:pr.

πŸš€ Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • New Features
    • Added a β€œflat/recommended” ESLint configuration preset for the plugin.
  • Refactor
    • Simplified plugin configuration structure for clearer, direct configuration and easier maintenance.
    • Improved typing of the exported plugin to better align with ESLint configurations.
  • Chores
    • Added a changeset documenting a minor version bump for the ESLint plugin and noting the configuration and typing improvements.

Use satisfies operator to verify that the shape of `plugins` matches
`ESLint.Plugin` (the extended version of it) while retaining its actual
shape.
Copy link

changeset-bot bot commented Sep 27, 2025

πŸ¦‹ Changeset detected

Latest commit: f35e108

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@tanstack/eslint-plugin-query Minor

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

Copy link
Contributor

coderabbitai bot commented Sep 27, 2025

Walkthrough

Introduces a new changeset entry and refactors the ESLint plugin export by inlining configs, adding a flat/recommended preset, removing the explicit Plugin type annotation, and performing a post-creation assignment to reference the plugin within its flat config.

Changes

Cohort / File(s) Summary
Changeset metadata
/.changeset/red-monkeys-attack.md
Adds a changeset for a minor bump of @tanstack/eslint-plugin-query noting improved exported plugin typing.
ESLint plugin export and configs
/packages/eslint-plugin-query/src/index.ts
Removes explicit Plugin type on export, inlines configs on the plugin object, adds configs['flat/recommended'] mirroring recommended rules, and assigns plugin into the flat config’s plugins['@tanstack/query'] after creation.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Developer
  participant ESLint as ESLint
  participant Plugin as @tanstack/eslint-plugin-query

  Dev->>ESLint: import { defineConfig }
  Dev->>Plugin: import plugin
  Note over Plugin: plugin object created with inlined configs
  Plugin->>Plugin: set configs['flat/recommended'][0].plugins['@tanstack/query'] = plugin
  Dev->>ESLint: defineConfig([...plugin.configs['flat/recommended']])
  ESLint->>ESLint: Load rules from plugin and apply recommended sets
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested labels

package: eslint-plugin-query

Suggested reviewers

  • Newbie012

Poem

I hopped through configs, tidy and bright,
Inlined my rules for a flatter flight.
A tiny tweak, a gentle nudgeβ€”
Now types align without a grudge.
Thump goes my paw: β€œShip it, delight!” πŸ‡βœ¨

Pre-merge checks and finishing touches

βœ… Passed checks (5 passed)
Check name Status Explanation
Linked Issues Check βœ… Passed The PR directly addresses the type compatibility issue described in issue #9689 by using TypeScript’s satisfies operator to enforce that the plugin export matches the ESLint.Plugin interfaceβ€”including its configs shapeβ€”thereby resolving the incompatibility with defineConfig(). This fulfills the linked issue’s requirement for compatible plugin config types.
Out of Scope Changes Check βœ… Passed All modifications are confined to the plugin export implementation and the associated changeset entry, with no alterations outside the scope of improving the plugin’s type or its configuration definitions. No unrelated files or functionality were touched.
Docstring Coverage βœ… Passed No functions found in the changes. Docstring coverage check skipped.
Title Check βœ… Passed The title β€œfeat(eslint-plugin): improve type of exported plugin” succinctly captures the primary change by indicating an enhancement to the exported plugin’s typing in the ESLint plugin package, and it adheres to conventional commit style without superfluous details.
Description Check βœ… Passed The pull request description faithfully follows the repository’s template by including a β€œπŸŽ― Changes” section with a clear summary of the TypeScript satisfies operator usage, a completed checklist verifying contribution steps and local tests, and a β€œπŸš€ Release Impact” section denoting the generated changeset and published code impact.
✨ Finishing touches
  • πŸ“ Generate Docstrings
πŸ§ͺ Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@mdmower-csnw mdmower-csnw changed the title Mdm eslintplugintype feat(eslint-plugin): Improve type of exported plugin Sep 27, 2025
@mdmower-csnw mdmower-csnw changed the title feat(eslint-plugin): Improve type of exported plugin feat(eslint-plugin): improve type of exported plugin Sep 27, 2025
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: 0

🧹 Nitpick comments (4)
.changeset/red-monkeys-attack.md (1)

2-5: Minor bump is appropriate; clarify the user-facing change.

The version bump to minor makes sense (new flat config + type improvements). Consider making the summary explicitly mention the new flat/recommended preset and the compatibility fix for eslint/config’s defineConfig(), and link the issue to auto-close.

Apply this diff to tighten the message:

-feat: improve type of exported plugin
+feat: add `flat/recommended` preset and improve exported plugin types
+
+This makes `@tanstack/eslint-plugin-query` configs compatible with `eslint/config`’s `defineConfig()` and fixes the type mismatch reported in #9689.
packages/eslint-plugin-query/src/index.ts (3)

32-49: Avoid post-creation mutation; build the flat config without placeholders.

The placeholder {} plus the follow-up assignment works but is brittle and makes the object temporarily invalid. Consider constructing via a small factory/IIFE so the plugin self-reference is wired at creation time.

Example refactor (keeps your satisfies pattern, removes the mutation):

// above: import/types stay the same

const recommendedRules: Linter.RulesRecord = {
  '@tanstack/query/exhaustive-deps': 'error',
  '@tanstack/query/no-rest-destructuring': 'warn',
  '@tanstack/query/stable-query-client': 'error',
  '@tanstack/query/no-unstable-deps': 'error',
  '@tanstack/query/infinite-query-property-order': 'error',
  '@tanstack/query/no-void-query-fn': 'error',
  '@tanstack/query/mutation-property-order': 'error',
};

export const plugin = (() => {
  const core = {
    meta: { name: '@tanstack/eslint-plugin-query' },
    rules,
  } satisfies ESLint.Plugin & { rules: Record<RuleKey, RuleModule<any, any, any>> };

  return {
    ...core,
    configs: {
      recommended: {
        plugins: ['@tanstack/query'],
        rules: recommendedRules,
      },
      'flat/recommended': [
        {
          name: '@tanstack/query/flat/recommended',
          plugins: { '@tanstack/query': core },
          rules: recommendedRules,
        },
      ],
    },
  } satisfies Plugin;
})();

Minimal alternative (if you prefer to keep structure): assign core instead of plugin in the flat config’s plugins map; ESLint.Plugin doesn’t require configs, so core suffices.


34-34: Nit: include scope in the flat config name.

For clarity in tooling/debug output, prefer @tanstack/query/flat/recommended.

Apply this diff:

-        name: 'tanstack/query/flat/recommended',
+        name: '@tanstack/query/flat/recommended',

53-53: Remove non-null assertion and guard the mutation (or drop it per refactor).

If you keep the current pattern, avoid ! and add a small guard to prevent future refactors from throwing.

-plugin.configs['flat/recommended'][0]!.plugins['@tanstack/query'] = plugin
+const firstFlat = plugin.configs['flat/recommended'][0]
+if (firstFlat?.plugins) {
+  firstFlat.plugins['@tanstack/query'] = plugin
+}

Alternatively, adopt the factory approach above and delete this line entirely.

πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 4f4866e and e9df771.

πŸ“’ Files selected for processing (2)
  • .changeset/red-monkeys-attack.md (1 hunks)
  • packages/eslint-plugin-query/src/index.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
πŸ“š Learning: 2025-08-19T03:18:18.303Z
Learnt from: oscartbeaumont
PR: TanStack/query#9564
File: packages/solid-query-devtools/src/production.tsx:2-3
Timestamp: 2025-08-19T03:18:18.303Z
Learning: In the solid-query-devtools package, the codebase uses a pattern of type-only default imports combined with typeof for component type annotations (e.g., `import type SolidQueryDevtoolsComp from './devtools'` followed by `typeof SolidQueryDevtoolsComp`). This pattern is consistently used across index.tsx and production.tsx files, and the maintainers prefer consistency over changing this approach.

Applied to files:

  • packages/eslint-plugin-query/src/index.ts
πŸ”‡ Additional comments (2)
packages/eslint-plugin-query/src/index.ts (2)

15-51: Good use of satisfies to keep runtime shape and strengthen types.

Inlining configs and validating the object with satisfies Plugin is clean and addresses the compatibility goal.


19-21: Legacy (eslintrc) recommended config looks correct.

plugins: ['@tanstack/query'] and the rules set align with the classic config expectations.

If you have examples/docs that import plugin.configs.recommended, verify a quick smoke run with ESLint 9.x using eslintrc to ensure no regressions in legacy users.

Copy link

nx-cloud bot commented Sep 27, 2025

View your CI Pipeline Execution β†— for commit f35e108

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... βœ… Succeeded 59s View β†—
nx run-many --target=build --exclude=examples/*... βœ… Succeeded 5s View β†—

☁️ Nx Cloud last updated this comment at 2025-09-27 23:08:31 UTC

Copy link

pkg-pr-new bot commented Sep 27, 2025

More templates

@tanstack/angular-query-experimental

npm i https://pkg.pr.new/@tanstack/angular-query-experimental@9700

@tanstack/eslint-plugin-query

npm i https://pkg.pr.new/@tanstack/eslint-plugin-query@9700

@tanstack/query-async-storage-persister

npm i https://pkg.pr.new/@tanstack/query-async-storage-persister@9700

@tanstack/query-broadcast-client-experimental

npm i https://pkg.pr.new/@tanstack/query-broadcast-client-experimental@9700

@tanstack/query-core

npm i https://pkg.pr.new/@tanstack/query-core@9700

@tanstack/query-devtools

npm i https://pkg.pr.new/@tanstack/query-devtools@9700

@tanstack/query-persist-client-core

npm i https://pkg.pr.new/@tanstack/query-persist-client-core@9700

@tanstack/query-sync-storage-persister

npm i https://pkg.pr.new/@tanstack/query-sync-storage-persister@9700

@tanstack/react-query

npm i https://pkg.pr.new/@tanstack/react-query@9700

@tanstack/react-query-devtools

npm i https://pkg.pr.new/@tanstack/react-query-devtools@9700

@tanstack/react-query-next-experimental

npm i https://pkg.pr.new/@tanstack/react-query-next-experimental@9700

@tanstack/react-query-persist-client

npm i https://pkg.pr.new/@tanstack/react-query-persist-client@9700

@tanstack/solid-query

npm i https://pkg.pr.new/@tanstack/solid-query@9700

@tanstack/solid-query-devtools

npm i https://pkg.pr.new/@tanstack/solid-query-devtools@9700

@tanstack/solid-query-persist-client

npm i https://pkg.pr.new/@tanstack/solid-query-persist-client@9700

@tanstack/svelte-query

npm i https://pkg.pr.new/@tanstack/svelte-query@9700

@tanstack/svelte-query-devtools

npm i https://pkg.pr.new/@tanstack/svelte-query-devtools@9700

@tanstack/svelte-query-persist-client

npm i https://pkg.pr.new/@tanstack/svelte-query-persist-client@9700

@tanstack/vue-query

npm i https://pkg.pr.new/@tanstack/vue-query@9700

@tanstack/vue-query-devtools

npm i https://pkg.pr.new/@tanstack/vue-query-devtools@9700

commit: f35e108

Copy link

codecov bot commented Sep 27, 2025

Codecov Report

❌ Patch coverage is 0% with 2 lines in your changes missing coverage. Please review.
βœ… Project coverage is 83.03%. Comparing base (da9e8bc) to head (f35e108).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             main    #9700       +/-   ##
===========================================
+ Coverage   46.41%   83.03%   +36.61%     
===========================================
  Files         214       19      -195     
  Lines        8499      560     -7939     
  Branches     1930      206     -1724     
===========================================
- Hits         3945      465     -3480     
+ Misses       4111       73     -4038     
+ Partials      443       22      -421     
Components Coverage Ξ”
@tanstack/angular-query-experimental βˆ… <ΓΈ> (βˆ…)
@tanstack/eslint-plugin-query 83.03% <0.00%> (ΓΈ)
@tanstack/query-async-storage-persister βˆ… <ΓΈ> (βˆ…)
@tanstack/query-broadcast-client-experimental βˆ… <ΓΈ> (βˆ…)
@tanstack/query-codemods βˆ… <ΓΈ> (βˆ…)
@tanstack/query-core βˆ… <ΓΈ> (βˆ…)
@tanstack/query-devtools βˆ… <ΓΈ> (βˆ…)
@tanstack/query-persist-client-core βˆ… <ΓΈ> (βˆ…)
@tanstack/query-sync-storage-persister βˆ… <ΓΈ> (βˆ…)
@tanstack/query-test-utils βˆ… <ΓΈ> (βˆ…)
@tanstack/react-query βˆ… <ΓΈ> (βˆ…)
@tanstack/react-query-devtools βˆ… <ΓΈ> (βˆ…)
@tanstack/react-query-next-experimental βˆ… <ΓΈ> (βˆ…)
@tanstack/react-query-persist-client βˆ… <ΓΈ> (βˆ…)
@tanstack/solid-query βˆ… <ΓΈ> (βˆ…)
@tanstack/solid-query-devtools βˆ… <ΓΈ> (βˆ…)
@tanstack/solid-query-persist-client βˆ… <ΓΈ> (βˆ…)
@tanstack/svelte-query βˆ… <ΓΈ> (βˆ…)
@tanstack/svelte-query-devtools βˆ… <ΓΈ> (βˆ…)
@tanstack/svelte-query-persist-client βˆ… <ΓΈ> (βˆ…)
@tanstack/vue-query βˆ… <ΓΈ> (βˆ…)
@tanstack/vue-query-devtools βˆ… <ΓΈ> (βˆ…)
πŸš€ New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • πŸ“¦ JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Member

@lachlancollins lachlancollins left a comment

Choose a reason for hiding this comment

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

This is great, thanks @mdmower-csnw !

@lachlancollins lachlancollins merged commit 832fac3 into TanStack:main Sep 27, 2025
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

@tanstack/eslint-plugin-query config types are incompatible with Eslint defineConfig() types
2 participants