Skip to content

Commit

Permalink
fix(eslint-plugin): ignore queryClient from exhaustive-check (#5291)
Browse files Browse the repository at this point in the history
* fix(eslint-plugin): ignore queryClient

* Update packages/eslint-plugin-query/src/rules/exhaustive-deps/exhaustive-deps.test.ts

---------

Co-authored-by: Dominik Dorfmeister <[email protected]>
  • Loading branch information
Newbie012 and TkDodo authored Apr 21, 2023
1 parent 3ec6693 commit 058f030
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AST_NODE_TYPES } from '@typescript-eslint/utils'
import { ASTUtils } from '../../utils/ast-utils'
import { createRule } from '../../utils/create-rule'
import { uniqueBy } from '../../utils/unique-by'
import { ExhaustiveDepsUtils } from './exhaustive-deps.utils'

const QUERY_KEY = 'queryKey'
const QUERY_FN = 'queryFn'
Expand Down Expand Up @@ -79,28 +80,19 @@ export const rule = createRule({

const sourceCode = context.getSourceCode()
const queryKeyValue = queryKeyNode
const reactComponent = ASTUtils.getReactComponentOrHookAncestor(context)
const refs = ASTUtils.getExternalRefs({
const externalRefs = ASTUtils.getExternalRefs({
scopeManager,
sourceCode,
node: queryFn.value,
}).filter((ref) => {
return (
reactComponent === undefined ||
ASTUtils.isDeclaredInNode({
scopeManager,
functionNode: reactComponent,
reference: ref,
})
)
})

const relevantRefs = refs.filter((ref) => {
return (
ref.identifier.name !== 'undefined' &&
ref.identifier.parent?.type !== AST_NODE_TYPES.NewExpression
)
})
const relevantRefs = externalRefs.filter((reference) =>
ExhaustiveDepsUtils.isRelevantReference({
context,
reference,
scopeManager,
}),
)

const existingKeys = ASTUtils.getNestedIdentifiers(queryKeyValue).map(
(identifier) => ASTUtils.mapKeyNodeToText(identifier, sourceCode),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,24 @@ ruleTester.run('exhaustive-deps', rule, {
}
`,
},
{
name: 'should ignore references of the queryClient',
code: `
const CONST_VAL = 1
function useHook() {
const queryClient = useQueryClient()
const kueryKlient = useQueryClient()
useQuery({
queryKey: ["foo"],
queryFn: () => {
doSomething(queryClient)
queryClient.invalidateQueries()
doSomethingSus(kueryKlient)
}
});
}
`,
},
],
invalid: [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { TSESLint } from '@typescript-eslint/utils'
import { AST_NODE_TYPES } from '@typescript-eslint/utils'
import { ASTUtils } from '../../utils/ast-utils'

export const ExhaustiveDepsUtils = {
isRelevantReference(params: {
context: Readonly<TSESLint.RuleContext<string, readonly unknown[]>>
reference: TSESLint.Scope.Reference
scopeManager: TSESLint.Scope.ScopeManager
}) {
const { reference, scopeManager, context } = params
const component = ASTUtils.getReactComponentOrHookAncestor(context)

if (
component !== undefined &&
!ASTUtils.isDeclaredInNode({
scopeManager,
reference,
functionNode: component,
})
) {
return false
}

return (
reference.identifier.name !== 'undefined' &&
reference.identifier.parent?.type !== AST_NODE_TYPES.NewExpression &&
!ExhaustiveDepsUtils.isQueryClientReference(reference)
)
},
isQueryClientReference(reference: TSESLint.Scope.Reference) {
const declarator = reference.resolved?.defs[0]?.node

return (
declarator?.type === AST_NODE_TYPES.VariableDeclarator &&
declarator.init?.type === AST_NODE_TYPES.CallExpression &&
declarator.init.callee.type === AST_NODE_TYPES.Identifier &&
declarator.init.callee.name === 'useQueryClient'
)
},
}

0 comments on commit 058f030

Please sign in to comment.