{"version":3,"file":"no-unstable-deps.rule.cjs","sources":["../../../../src/rules/no-unstable-deps/no-unstable-deps.rule.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport type { ExtraRuleDocs } from '../../types';\nimport { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';\nimport { createClientNameRegex } from '../../utils/create-client-name-regex';\nimport { getDocsUrl } from '../../utils/get-docs-url';\nimport { getRootIdentifier } from '../../utils/get-root-identifier';\n\nexport const name = 'no-unstable-deps';\n\nexport const reactHookNames = ['useEffect', 'useCallback', 'useMemo'];\nexport const useQueryHookNames = [\n  'useQuery',\n  'useSuspenseQuery',\n  'useQueries',\n  'useSuspenseQueries',\n  'useInfiniteQuery',\n  'useSuspenseInfiniteQuery',\n];\nconst allHookNames = ['useMutation', ...useQueryHookNames];\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl);\n\nexport const rule = createRule({\n  name,\n  meta: {\n    type: 'problem',\n    docs: {\n      description:\n        'Disallow putting the result of query hooks directly in a React hook dependency array',\n      recommended: 'error',\n    },\n    messages: {\n      noUnstableDeps: `The result of {{queryHook}} is not referentially stable, so don't pass it directly into the dependencies array of {{reactHook}}. Instead, destructure the return value of {{queryHook}} and pass the destructured values into the dependency array of {{reactHook}}.`,\n    },\n    schema: [\n      {\n        type: 'object',\n        properties: {\n          clientNamePattern: { type: 'string' },\n        },\n        additionalProperties: false,\n      },\n    ],\n  },\n  defaultOptions: [{}],\n\n  create: (context) => {\n    const option =\n      (context.options[0] as { clientNamePattern?: string } | undefined) ?? {};\n    const clientRegex = createClientNameRegex(option.clientNamePattern);\n\n    const trackedVariables: Record<string, string> = {};\n    const hookAliasMap: Record<string, string> = {};\n\n    function getReactHook(node: TSESTree.CallExpression): string | undefined {\n      if (node.callee.type === 'Identifier') {\n        const calleeName = node.callee.name;\n        if (reactHookNames.includes(calleeName) || calleeName in hookAliasMap) {\n          // Return the actually used identifier (could be alias)\n          return calleeName;\n        }\n      } else if (\n        node.callee.type === 'MemberExpression' &&\n        node.callee.object.type === 'Identifier' &&\n        node.callee.object.name === 'React' &&\n        node.callee.property.type === 'Identifier' &&\n        reactHookNames.includes(node.callee.property.name)\n      ) {\n        return node.callee.property.name;\n      }\n      return undefined;\n    }\n\n    return {\n      ImportDeclaration(node: TSESTree.ImportDeclaration) {\n        if (\n          node.specifiers.length > 0 &&\n          node.importKind === 'value' &&\n          node.source.value === 'React'\n        ) {\n          node.specifiers.forEach((specifier) => {\n            if (\n              specifier.type === AST_NODE_TYPES.ImportSpecifier &&\n              specifier.imported.type === AST_NODE_TYPES.Identifier &&\n              reactHookNames.includes(specifier.imported.name)\n            ) {\n              hookAliasMap[specifier.local.name] = specifier.imported.name;\n            }\n          });\n        }\n      },\n\n      VariableDeclarator(node) {\n        if (node.init?.type !== AST_NODE_TYPES.CallExpression) return;\n        const hook = isQueryHookFromClient(clientRegex, node.init);\n        if (!hook) return;\n        if (node.id.type === AST_NODE_TYPES.Identifier) {\n          trackedVariables[node.id.name] = hook;\n        }\n      },\n      CallExpression: (node) => {\n        const reactHook = getReactHook(node);\n        if (!reactHook) return;\n        if (node.arguments.length <= 1) return;\n        if (node.arguments[1]?.type !== AST_NODE_TYPES.ArrayExpression) return;\n\n        const depsArray = node.arguments[1].elements;\n        depsArray.forEach((dep) => {\n          if (dep?.type !== AST_NODE_TYPES.Identifier) return;\n          const queryHook = trackedVariables[dep.name];\n          if (!queryHook) return;\n          context.report({\n            node: dep,\n            messageId: 'noUnstableDeps',\n            data: {\n              queryHook,\n              reactHook,\n            },\n          });\n        });\n      },\n    };\n  },\n});\n\nfunction isQueryHookFromClient(\n  clientRegex: RegExp,\n  call: TSESTree.CallExpression\n): string | null {\n  if (call.callee.type !== AST_NODE_TYPES.MemberExpression) return null;\n  const member = call.callee;\n  if (member.property.type !== AST_NODE_TYPES.Identifier) return null;\n  const hook = member.property.name;\n  if (!allHookNames.includes(hook)) return null;\n  const root = getRootIdentifier(member.object);\n  if (!root) return null;\n  return clientRegex.test(root.name) ? hook : null;\n}\n"],"names":["name","reactHookNames","useQueryHookNames","allHookNames","createRule","ESLintUtils","RuleCreator","getDocsUrl","rule","meta","type","docs","description","recommended","messages","noUnstableDeps","schema","properties","clientNamePattern","additionalProperties","defaultOptions","create","context","option","options","clientRegex","createClientNameRegex","trackedVariables","hookAliasMap","getReactHook","node","callee","calleeName","includes","object","property","undefined","ImportDeclaration","specifiers","length","importKind","source","value","forEach","specifier","AST_NODE_TYPES","ImportSpecifier","imported","Identifier","local","VariableDeclarator","init","CallExpression","hook","isQueryHookFromClient","id","reactHook","arguments","ArrayExpression","depsArray","elements","dep","queryHook","report","messageId","data","call","MemberExpression","member","root","getRootIdentifier","test"],"mappings":"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"}