feat(eslint-plugin): improve type of exported plugin#9700
feat(eslint-plugin): improve type of exported plugin#9700lachlancollins merged 3 commits intoTanStack:mainfrom
Conversation
Use satisfies operator to verify that the shape of `plugins` matches `ESLint.Plugin` (the extended version of it) while retaining its actual shape.
🦋 Changeset detectedLatest commit: f35e108 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
WalkthroughIntroduces 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
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
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate 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. Comment |
There was a problem hiding this comment.
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/recommendedpreset and the compatibility fix foreslint/config’sdefineConfig(), 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
satisfiespattern, 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
coreinstead ofpluginin the flat config’spluginsmap;ESLint.Plugindoesn’t requireconfigs, socoresuffices.
34-34: Nit: include scope in the flat configname.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
📒 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 ofsatisfiesto keep runtime shape and strengthen types.Inlining
configsand validating the object withsatisfies Pluginis clean and addresses the compatibility goal.
19-21: Legacy (eslintrc)recommendedconfig 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.
|
View your CI Pipeline Execution ↗ for commit f35e108
☁️ Nx Cloud last updated this comment at |
More templates
@tanstack/angular-query-experimental
@tanstack/eslint-plugin-query
@tanstack/query-async-storage-persister
@tanstack/query-broadcast-client-experimental
@tanstack/query-core
@tanstack/query-devtools
@tanstack/query-persist-client-core
@tanstack/query-sync-storage-persister
@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
commit: |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ 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
🚀 New features to boost your workflow:
|
lachlancollins
left a comment
There was a problem hiding this comment.
This is great, thanks @mdmower-csnw !
* feat(eslint-plugin): Improve type of exported plugin Use satisfies operator to verify that the shape of `plugins` matches `ESLint.Plugin` (the extended version of it) while retaining its actual shape. * add changeset --------- Co-authored-by: Lachlan Collins <[email protected]>
🎯 Changes
Use TypeScript's
satisfiesoperator to verify that the shape ofpluginsmatchesESLint.Plugin(the extended version of it) while retaining its actual shape.Fixes #9689
✅ Checklist
pnpm test:pr.🚀 Release Impact
Summary by CodeRabbit