@tanstack/eslint-plugin-query 5.71.5 → 5.72.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/dist/index.cjs +1002 -0
  2. package/dist/index.cjs.map +1 -0
  3. package/dist/index.d.cts +24 -0
  4. package/dist/index.d.ts +24 -0
  5. package/dist/index.js +968 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/rules.cjs +967 -0
  8. package/dist/rules.cjs.map +1 -0
  9. package/dist/rules.js +929 -0
  10. package/dist/rules.js.map +1 -0
  11. package/package.json +12 -12
  12. package/dist/cjs/index.cjs +0 -38
  13. package/dist/cjs/index.cjs.map +0 -1
  14. package/dist/cjs/index.d.cts +0 -13
  15. package/dist/cjs/rules/exhaustive-deps/exhaustive-deps.rule.cjs +0 -134
  16. package/dist/cjs/rules/exhaustive-deps/exhaustive-deps.rule.cjs.map +0 -1
  17. package/dist/cjs/rules/exhaustive-deps/exhaustive-deps.rule.d.cts +0 -4
  18. package/dist/cjs/rules/exhaustive-deps/exhaustive-deps.utils.cjs +0 -26
  19. package/dist/cjs/rules/exhaustive-deps/exhaustive-deps.utils.cjs.map +0 -1
  20. package/dist/cjs/rules/exhaustive-deps/exhaustive-deps.utils.d.cts +0 -10
  21. package/dist/cjs/rules/infinite-query-property-order/constants.cjs +0 -13
  22. package/dist/cjs/rules/infinite-query-property-order/constants.cjs.map +0 -1
  23. package/dist/cjs/rules/infinite-query-property-order/constants.d.cts +0 -4
  24. package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.rule.cjs +0 -88
  25. package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.rule.cjs.map +0 -1
  26. package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.rule.d.cts +0 -4
  27. package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.utils.cjs +0 -47
  28. package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.utils.cjs.map +0 -1
  29. package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.utils.d.cts +0 -1
  30. package/dist/cjs/rules/no-rest-destructuring/no-rest-destructuring.rule.cjs +0 -92
  31. package/dist/cjs/rules/no-rest-destructuring/no-rest-destructuring.rule.cjs.map +0 -1
  32. package/dist/cjs/rules/no-rest-destructuring/no-rest-destructuring.rule.d.cts +0 -4
  33. package/dist/cjs/rules/no-rest-destructuring/no-rest-destructuring.utils.cjs +0 -13
  34. package/dist/cjs/rules/no-rest-destructuring/no-rest-destructuring.utils.cjs.map +0 -1
  35. package/dist/cjs/rules/no-rest-destructuring/no-rest-destructuring.utils.d.cts +0 -4
  36. package/dist/cjs/rules/no-unstable-deps/no-unstable-deps.rule.cjs +0 -93
  37. package/dist/cjs/rules/no-unstable-deps/no-unstable-deps.rule.cjs.map +0 -1
  38. package/dist/cjs/rules/no-unstable-deps/no-unstable-deps.rule.d.cts +0 -6
  39. package/dist/cjs/rules/stable-query-client/stable-query-client.rule.cjs +0 -71
  40. package/dist/cjs/rules/stable-query-client/stable-query-client.rule.cjs.map +0 -1
  41. package/dist/cjs/rules/stable-query-client/stable-query-client.rule.d.cts +0 -4
  42. package/dist/cjs/rules.cjs +0 -16
  43. package/dist/cjs/rules.cjs.map +0 -1
  44. package/dist/cjs/rules.d.cts +0 -3
  45. package/dist/cjs/types.d.cts +0 -3
  46. package/dist/cjs/utils/ast-utils.cjs +0 -267
  47. package/dist/cjs/utils/ast-utils.cjs.map +0 -1
  48. package/dist/cjs/utils/ast-utils.d.cts +0 -38
  49. package/dist/cjs/utils/detect-react-query-imports.cjs +0 -55
  50. package/dist/cjs/utils/detect-react-query-imports.cjs.map +0 -1
  51. package/dist/cjs/utils/detect-react-query-imports.d.cts +0 -11
  52. package/dist/cjs/utils/get-docs-url.cjs +0 -5
  53. package/dist/cjs/utils/get-docs-url.cjs.map +0 -1
  54. package/dist/cjs/utils/get-docs-url.d.cts +0 -1
  55. package/dist/cjs/utils/unique-by.cjs +0 -7
  56. package/dist/cjs/utils/unique-by.cjs.map +0 -1
  57. package/dist/cjs/utils/unique-by.d.cts +0 -1
  58. package/dist/esm/index.d.ts +0 -13
  59. package/dist/esm/index.js +0 -39
  60. package/dist/esm/index.js.map +0 -1
  61. package/dist/esm/rules/exhaustive-deps/exhaustive-deps.rule.d.ts +0 -4
  62. package/dist/esm/rules/exhaustive-deps/exhaustive-deps.rule.js +0 -134
  63. package/dist/esm/rules/exhaustive-deps/exhaustive-deps.rule.js.map +0 -1
  64. package/dist/esm/rules/exhaustive-deps/exhaustive-deps.utils.d.ts +0 -10
  65. package/dist/esm/rules/exhaustive-deps/exhaustive-deps.utils.js +0 -26
  66. package/dist/esm/rules/exhaustive-deps/exhaustive-deps.utils.js.map +0 -1
  67. package/dist/esm/rules/infinite-query-property-order/constants.d.ts +0 -4
  68. package/dist/esm/rules/infinite-query-property-order/constants.js +0 -13
  69. package/dist/esm/rules/infinite-query-property-order/constants.js.map +0 -1
  70. package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.rule.d.ts +0 -4
  71. package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.rule.js +0 -88
  72. package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.rule.js.map +0 -1
  73. package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.utils.d.ts +0 -1
  74. package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.utils.js +0 -47
  75. package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.utils.js.map +0 -1
  76. package/dist/esm/rules/no-rest-destructuring/no-rest-destructuring.rule.d.ts +0 -4
  77. package/dist/esm/rules/no-rest-destructuring/no-rest-destructuring.rule.js +0 -92
  78. package/dist/esm/rules/no-rest-destructuring/no-rest-destructuring.rule.js.map +0 -1
  79. package/dist/esm/rules/no-rest-destructuring/no-rest-destructuring.utils.d.ts +0 -4
  80. package/dist/esm/rules/no-rest-destructuring/no-rest-destructuring.utils.js +0 -13
  81. package/dist/esm/rules/no-rest-destructuring/no-rest-destructuring.utils.js.map +0 -1
  82. package/dist/esm/rules/no-unstable-deps/no-unstable-deps.rule.d.ts +0 -6
  83. package/dist/esm/rules/no-unstable-deps/no-unstable-deps.rule.js +0 -93
  84. package/dist/esm/rules/no-unstable-deps/no-unstable-deps.rule.js.map +0 -1
  85. package/dist/esm/rules/stable-query-client/stable-query-client.rule.d.ts +0 -4
  86. package/dist/esm/rules/stable-query-client/stable-query-client.rule.js +0 -71
  87. package/dist/esm/rules/stable-query-client/stable-query-client.rule.js.map +0 -1
  88. package/dist/esm/rules.d.ts +0 -3
  89. package/dist/esm/rules.js +0 -16
  90. package/dist/esm/rules.js.map +0 -1
  91. package/dist/esm/types.d.ts +0 -3
  92. package/dist/esm/utils/ast-utils.d.ts +0 -38
  93. package/dist/esm/utils/ast-utils.js +0 -267
  94. package/dist/esm/utils/ast-utils.js.map +0 -1
  95. package/dist/esm/utils/detect-react-query-imports.d.ts +0 -11
  96. package/dist/esm/utils/detect-react-query-imports.js +0 -55
  97. package/dist/esm/utils/detect-react-query-imports.js.map +0 -1
  98. package/dist/esm/utils/get-docs-url.d.ts +0 -1
  99. package/dist/esm/utils/get-docs-url.js +0 -5
  100. package/dist/esm/utils/get-docs-url.js.map +0 -1
  101. package/dist/esm/utils/unique-by.d.ts +0 -1
  102. package/dist/esm/utils/unique-by.js +0 -7
  103. package/dist/esm/utils/unique-by.js.map +0 -1
  104. package/src/index.ts +0 -52
  105. package/src/rules/exhaustive-deps/exhaustive-deps.rule.ts +0 -184
  106. package/src/rules/exhaustive-deps/exhaustive-deps.utils.ts +0 -41
  107. package/src/rules/infinite-query-property-order/constants.ts +0 -17
  108. package/src/rules/infinite-query-property-order/infinite-query-property-order.rule.ts +0 -107
  109. package/src/rules/infinite-query-property-order/infinite-query-property-order.utils.ts +0 -67
  110. package/src/rules/no-rest-destructuring/no-rest-destructuring.rule.ts +0 -115
  111. package/src/rules/no-rest-destructuring/no-rest-destructuring.utils.ts +0 -11
  112. package/src/rules/no-unstable-deps/no-unstable-deps.rule.ts +0 -129
  113. package/src/rules/stable-query-client/stable-query-client.rule.ts +0 -88
  114. package/src/rules.ts +0 -23
  115. package/src/types.ts +0 -3
  116. package/src/utils/ast-utils.ts +0 -391
  117. package/src/utils/detect-react-query-imports.ts +0 -97
  118. package/src/utils/get-docs-url.ts +0 -2
  119. package/src/utils/unique-by.ts +0 -3
@@ -1,88 +0,0 @@
1
- import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'
2
- import { ASTUtils } from '../../utils/ast-utils'
3
- import { getDocsUrl } from '../../utils/get-docs-url'
4
- import { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'
5
- import type { TSESLint } from '@typescript-eslint/utils'
6
- import type { ExtraRuleDocs } from '../../types'
7
-
8
- export const name = 'stable-query-client'
9
-
10
- const createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)
11
-
12
- export const rule = createRule({
13
- name,
14
- meta: {
15
- type: 'problem',
16
- docs: {
17
- description: 'Makes sure that QueryClient is stable',
18
- recommended: 'error',
19
- },
20
- messages: {
21
- unstable: [
22
- 'QueryClient is not stable. It should be either extracted from the component or wrapped in React.useState.',
23
- 'See https://tkdodo.eu/blog/react-query-fa-qs#2-the-queryclient-is-not-stable',
24
- ].join('\n'),
25
- fixTo: 'Fix to {{result}}',
26
- },
27
- hasSuggestions: true,
28
- fixable: 'code',
29
- schema: [],
30
- },
31
- defaultOptions: [],
32
-
33
- create: detectTanstackQueryImports((context, _, helpers) => {
34
- return {
35
- NewExpression: (node) => {
36
- if (
37
- node.callee.type !== AST_NODE_TYPES.Identifier ||
38
- node.callee.name !== 'QueryClient' ||
39
- node.parent.type !== AST_NODE_TYPES.VariableDeclarator ||
40
- !helpers.isSpecificTanstackQueryImport(
41
- node.callee,
42
- '@tanstack/react-query',
43
- )
44
- ) {
45
- return
46
- }
47
-
48
- const fnAncestor = ASTUtils.getFunctionAncestor(
49
- context.sourceCode,
50
- node,
51
- )
52
- const isReactServerComponent = fnAncestor?.async === true
53
-
54
- if (
55
- !ASTUtils.isValidReactComponentOrHookName(fnAncestor?.id) ||
56
- isReactServerComponent
57
- ) {
58
- return
59
- }
60
-
61
- context.report({
62
- node: node.parent,
63
- messageId: 'unstable',
64
- fix: (() => {
65
- const { parent } = node
66
-
67
- if (parent.id.type !== AST_NODE_TYPES.Identifier) {
68
- return
69
- }
70
-
71
- // we need the fallbacks for backwards compat with eslint < 8.37.0
72
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
73
- const sourceCode = context.sourceCode ?? context.getSourceCode()
74
- const nodeText = sourceCode.getText(node)
75
- const variableName = parent.id.name
76
-
77
- return (fixer: TSESLint.RuleFixer) => {
78
- return fixer.replaceTextRange(
79
- [parent.range[0], parent.range[1]],
80
- `[${variableName}] = React.useState(() => ${nodeText})`,
81
- )
82
- }
83
- })(),
84
- })
85
- },
86
- }
87
- }),
88
- })
package/src/rules.ts DELETED
@@ -1,23 +0,0 @@
1
- import * as exhaustiveDeps from './rules/exhaustive-deps/exhaustive-deps.rule'
2
- import * as stableQueryClient from './rules/stable-query-client/stable-query-client.rule'
3
- import * as noRestDestructuring from './rules/no-rest-destructuring/no-rest-destructuring.rule'
4
- import * as noUnstableDeps from './rules/no-unstable-deps/no-unstable-deps.rule'
5
- import * as infiniteQueryPropertyOrder from './rules/infinite-query-property-order/infinite-query-property-order.rule'
6
- import type { ESLintUtils } from '@typescript-eslint/utils'
7
- import type { ExtraRuleDocs } from './types'
8
-
9
- export const rules: Record<
10
- string,
11
- ESLintUtils.RuleModule<
12
- string,
13
- ReadonlyArray<unknown>,
14
- ExtraRuleDocs,
15
- ESLintUtils.RuleListener
16
- >
17
- > = {
18
- [exhaustiveDeps.name]: exhaustiveDeps.rule,
19
- [stableQueryClient.name]: stableQueryClient.rule,
20
- [noRestDestructuring.name]: noRestDestructuring.rule,
21
- [noUnstableDeps.name]: noUnstableDeps.rule,
22
- [infiniteQueryPropertyOrder.name]: infiniteQueryPropertyOrder.rule,
23
- }
package/src/types.ts DELETED
@@ -1,3 +0,0 @@
1
- export type ExtraRuleDocs = {
2
- recommended: 'strict' | 'error' | 'warn'
3
- }
@@ -1,391 +0,0 @@
1
- import { AST_NODE_TYPES } from '@typescript-eslint/utils'
2
- import { uniqueBy } from './unique-by'
3
- import type { TSESLint, TSESTree } from '@typescript-eslint/utils'
4
-
5
- export const ASTUtils = {
6
- isNodeOfOneOf<T extends AST_NODE_TYPES>(
7
- node: TSESTree.Node,
8
- types: ReadonlyArray<T>,
9
- ): node is TSESTree.Node & { type: T } {
10
- return types.includes(node.type as T)
11
- },
12
- isIdentifier(node: TSESTree.Node): node is TSESTree.Identifier {
13
- return node.type === AST_NODE_TYPES.Identifier
14
- },
15
- isIdentifierWithName(
16
- node: TSESTree.Node,
17
- name: string,
18
- ): node is TSESTree.Identifier {
19
- return ASTUtils.isIdentifier(node) && node.name === name
20
- },
21
- isIdentifierWithOneOfNames<T extends Array<string>>(
22
- node: TSESTree.Node,
23
- name: T,
24
- ): node is TSESTree.Identifier & { name: T[number] } {
25
- return ASTUtils.isIdentifier(node) && name.includes(node.name)
26
- },
27
- isProperty(node: TSESTree.Node): node is TSESTree.Property {
28
- return node.type === AST_NODE_TYPES.Property
29
- },
30
- isObjectExpression(node: TSESTree.Node): node is TSESTree.ObjectExpression {
31
- return node.type === AST_NODE_TYPES.ObjectExpression
32
- },
33
- isPropertyWithIdentifierKey(
34
- node: TSESTree.Node,
35
- key: string,
36
- ): node is TSESTree.Property {
37
- return (
38
- ASTUtils.isProperty(node) && ASTUtils.isIdentifierWithName(node.key, key)
39
- )
40
- },
41
- findPropertyWithIdentifierKey(
42
- properties: Array<TSESTree.ObjectLiteralElement>,
43
- key: string,
44
- ): TSESTree.Property | undefined {
45
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
46
- return properties.find((x) =>
47
- ASTUtils.isPropertyWithIdentifierKey(x, key),
48
- ) as TSESTree.Property | undefined
49
- },
50
- getNestedIdentifiers(node: TSESTree.Node): Array<TSESTree.Identifier> {
51
- const identifiers: Array<TSESTree.Identifier> = []
52
-
53
- if (ASTUtils.isIdentifier(node)) {
54
- identifiers.push(node)
55
- }
56
-
57
- if ('arguments' in node) {
58
- node.arguments.forEach((x) => {
59
- identifiers.push(...ASTUtils.getNestedIdentifiers(x))
60
- })
61
- }
62
-
63
- if ('elements' in node) {
64
- node.elements.forEach((x) => {
65
- if (x !== null) {
66
- identifiers.push(...ASTUtils.getNestedIdentifiers(x))
67
- }
68
- })
69
- }
70
-
71
- if ('properties' in node) {
72
- node.properties.forEach((x) => {
73
- identifiers.push(...ASTUtils.getNestedIdentifiers(x))
74
- })
75
- }
76
-
77
- if ('expressions' in node) {
78
- node.expressions.forEach((x) => {
79
- identifiers.push(...ASTUtils.getNestedIdentifiers(x))
80
- })
81
- }
82
-
83
- if ('left' in node) {
84
- identifiers.push(...ASTUtils.getNestedIdentifiers(node.left))
85
- }
86
-
87
- if ('right' in node) {
88
- identifiers.push(...ASTUtils.getNestedIdentifiers(node.right))
89
- }
90
-
91
- if (node.type === AST_NODE_TYPES.Property) {
92
- identifiers.push(...ASTUtils.getNestedIdentifiers(node.value))
93
- }
94
-
95
- if (node.type === AST_NODE_TYPES.SpreadElement) {
96
- identifiers.push(...ASTUtils.getNestedIdentifiers(node.argument))
97
- }
98
-
99
- if (node.type === AST_NODE_TYPES.MemberExpression) {
100
- identifiers.push(...ASTUtils.getNestedIdentifiers(node.object))
101
- }
102
-
103
- if (node.type === AST_NODE_TYPES.UnaryExpression) {
104
- identifiers.push(...ASTUtils.getNestedIdentifiers(node.argument))
105
- }
106
-
107
- if (node.type === AST_NODE_TYPES.ChainExpression) {
108
- identifiers.push(...ASTUtils.getNestedIdentifiers(node.expression))
109
- }
110
-
111
- if (node.type === AST_NODE_TYPES.TSNonNullExpression) {
112
- identifiers.push(...ASTUtils.getNestedIdentifiers(node.expression))
113
- }
114
-
115
- if (node.type === AST_NODE_TYPES.ArrowFunctionExpression) {
116
- identifiers.push(...ASTUtils.getNestedIdentifiers(node.body))
117
- }
118
-
119
- if (node.type === AST_NODE_TYPES.FunctionExpression) {
120
- identifiers.push(...ASTUtils.getNestedIdentifiers(node.body))
121
- }
122
-
123
- if (node.type === AST_NODE_TYPES.BlockStatement) {
124
- identifiers.push(
125
- ...node.body.map((body) => ASTUtils.getNestedIdentifiers(body)).flat(),
126
- )
127
- }
128
-
129
- if (node.type === AST_NODE_TYPES.ReturnStatement && node.argument) {
130
- identifiers.push(...ASTUtils.getNestedIdentifiers(node.argument))
131
- }
132
-
133
- return identifiers
134
- },
135
- isAncestorIsCallee(identifier: TSESTree.Node) {
136
- let previousNode = identifier
137
- let currentNode = identifier.parent
138
-
139
- while (currentNode !== undefined) {
140
- if (
141
- currentNode.type === AST_NODE_TYPES.CallExpression &&
142
- currentNode.callee === previousNode
143
- ) {
144
- return true
145
- }
146
-
147
- if (currentNode.type !== AST_NODE_TYPES.MemberExpression) {
148
- return false
149
- }
150
-
151
- previousNode = currentNode
152
- currentNode = currentNode.parent
153
- }
154
-
155
- return false
156
- },
157
- traverseUpOnly(
158
- identifier: TSESTree.Node,
159
- allowedNodeTypes: Array<AST_NODE_TYPES>,
160
- ): TSESTree.Node {
161
- const parent = identifier.parent
162
-
163
- if (parent !== undefined && allowedNodeTypes.includes(parent.type)) {
164
- return ASTUtils.traverseUpOnly(parent, allowedNodeTypes)
165
- }
166
-
167
- return identifier
168
- },
169
- isDeclaredInNode(params: {
170
- functionNode: TSESTree.Node
171
- reference: TSESLint.Scope.Reference
172
- scopeManager: TSESLint.Scope.ScopeManager
173
- }) {
174
- const { functionNode, reference, scopeManager } = params
175
- const scope = scopeManager.acquire(functionNode)
176
-
177
- if (scope === null) {
178
- return false
179
- }
180
-
181
- return scope.set.has(reference.identifier.name)
182
- },
183
- getExternalRefs(params: {
184
- scopeManager: TSESLint.Scope.ScopeManager
185
- sourceCode: Readonly<TSESLint.SourceCode>
186
- node: TSESTree.Node
187
- }): Array<TSESLint.Scope.Reference> {
188
- const { scopeManager, sourceCode, node } = params
189
- const scope = scopeManager.acquire(node)
190
-
191
- if (scope === null) {
192
- return []
193
- }
194
-
195
- const references = scope.references
196
- .filter((x) => x.isRead() && !scope.set.has(x.identifier.name))
197
- .map((x) => {
198
- const referenceNode = ASTUtils.traverseUpOnly(x.identifier, [
199
- AST_NODE_TYPES.MemberExpression,
200
- AST_NODE_TYPES.Identifier,
201
- ])
202
-
203
- return {
204
- variable: x,
205
- node: referenceNode,
206
- text: sourceCode.getText(referenceNode),
207
- }
208
- })
209
-
210
- const localRefIds = new Set(
211
- [...scope.set.values()].map((x) => sourceCode.getText(x.identifiers[0])),
212
- )
213
-
214
- const externalRefs = references.filter(
215
- (x) => x.variable.resolved === null || !localRefIds.has(x.text),
216
- )
217
-
218
- return uniqueBy(externalRefs, (x) => x.text).map((x) => x.variable)
219
- },
220
- mapKeyNodeToText(
221
- node: TSESTree.Node,
222
- sourceCode: Readonly<TSESLint.SourceCode>,
223
- ) {
224
- return sourceCode.getText(
225
- ASTUtils.traverseUpOnly(node, [
226
- AST_NODE_TYPES.MemberExpression,
227
- AST_NODE_TYPES.TSNonNullExpression,
228
- AST_NODE_TYPES.Identifier,
229
- ]),
230
- )
231
- },
232
- mapKeyNodeToBaseText(
233
- node: TSESTree.Node,
234
- sourceCode: Readonly<TSESLint.SourceCode>,
235
- ) {
236
- return ASTUtils.mapKeyNodeToText(node, sourceCode).replace(
237
- /(?:\?(\.)|!)/g,
238
- '$1',
239
- )
240
- },
241
- isValidReactComponentOrHookName(
242
- identifier: TSESTree.Identifier | null | undefined,
243
- ) {
244
- return (
245
- identifier !== null &&
246
- identifier !== undefined &&
247
- /^(use|[A-Z])/.test(identifier.name)
248
- )
249
- },
250
- getFunctionAncestor(
251
- sourceCode: Readonly<TSESLint.SourceCode>,
252
- node: TSESTree.Node,
253
- ) {
254
- for (const ancestor of sourceCode.getAncestors(node)) {
255
- if (
256
- ASTUtils.isNodeOfOneOf(ancestor, [
257
- AST_NODE_TYPES.FunctionDeclaration,
258
- AST_NODE_TYPES.FunctionExpression,
259
- AST_NODE_TYPES.ArrowFunctionExpression,
260
- ])
261
- ) {
262
- return ancestor
263
- }
264
-
265
- if (
266
- ancestor.parent?.type === AST_NODE_TYPES.VariableDeclarator &&
267
- ancestor.parent.id.type === AST_NODE_TYPES.Identifier &&
268
- ASTUtils.isNodeOfOneOf(ancestor, [
269
- AST_NODE_TYPES.FunctionDeclaration,
270
- AST_NODE_TYPES.FunctionExpression,
271
- AST_NODE_TYPES.ArrowFunctionExpression,
272
- ])
273
- ) {
274
- return ancestor
275
- }
276
- }
277
-
278
- return undefined
279
- },
280
- getReferencedExpressionByIdentifier(params: {
281
- node: TSESTree.Node
282
- context: Readonly<TSESLint.RuleContext<string, ReadonlyArray<unknown>>>
283
- }) {
284
- const { node, context } = params
285
-
286
- // we need the fallbacks for backwards compat with eslint < 8.37.0
287
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
288
- const sourceCode = context.sourceCode ?? context.getSourceCode()
289
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
290
- const scope = context.sourceCode.getScope(node)
291
- ? sourceCode.getScope(node)
292
- : context.getScope()
293
-
294
- const resolvedNode = scope.references.find((ref) => ref.identifier === node)
295
- ?.resolved?.defs[0]?.node
296
-
297
- if (resolvedNode?.type !== AST_NODE_TYPES.VariableDeclarator) {
298
- return null
299
- }
300
-
301
- return resolvedNode.init
302
- },
303
- getClosestVariableDeclarator(node: TSESTree.Node) {
304
- let currentNode: TSESTree.Node | undefined = node
305
-
306
- while (currentNode.type !== AST_NODE_TYPES.Program) {
307
- if (currentNode.type === AST_NODE_TYPES.VariableDeclarator) {
308
- return currentNode
309
- }
310
-
311
- currentNode = currentNode.parent
312
- }
313
-
314
- return undefined
315
- },
316
- getNestedReturnStatements(
317
- node: TSESTree.Node,
318
- ): Array<TSESTree.ReturnStatement> {
319
- const returnStatements: Array<TSESTree.ReturnStatement> = []
320
-
321
- if (node.type === AST_NODE_TYPES.ReturnStatement) {
322
- returnStatements.push(node)
323
- }
324
-
325
- if ('body' in node && node.body !== undefined && node.body !== null) {
326
- Array.isArray(node.body)
327
- ? node.body.forEach((x) => {
328
- returnStatements.push(...ASTUtils.getNestedReturnStatements(x))
329
- })
330
- : returnStatements.push(
331
- ...ASTUtils.getNestedReturnStatements(node.body),
332
- )
333
- }
334
-
335
- if ('consequent' in node) {
336
- Array.isArray(node.consequent)
337
- ? node.consequent.forEach((x) => {
338
- returnStatements.push(...ASTUtils.getNestedReturnStatements(x))
339
- })
340
- : returnStatements.push(
341
- ...ASTUtils.getNestedReturnStatements(node.consequent),
342
- )
343
- }
344
-
345
- if ('alternate' in node && node.alternate !== null) {
346
- Array.isArray(node.alternate)
347
- ? node.alternate.forEach((x) => {
348
- returnStatements.push(...ASTUtils.getNestedReturnStatements(x))
349
- })
350
- : returnStatements.push(
351
- ...ASTUtils.getNestedReturnStatements(node.alternate),
352
- )
353
- }
354
-
355
- if ('cases' in node) {
356
- node.cases.forEach((x) => {
357
- returnStatements.push(...ASTUtils.getNestedReturnStatements(x))
358
- })
359
- }
360
-
361
- if ('block' in node) {
362
- returnStatements.push(...ASTUtils.getNestedReturnStatements(node.block))
363
- }
364
-
365
- if ('handler' in node && node.handler !== null) {
366
- returnStatements.push(...ASTUtils.getNestedReturnStatements(node.handler))
367
- }
368
-
369
- if ('finalizer' in node && node.finalizer !== null) {
370
- returnStatements.push(
371
- ...ASTUtils.getNestedReturnStatements(node.finalizer),
372
- )
373
- }
374
-
375
- if (
376
- 'expression' in node &&
377
- node.expression !== true &&
378
- node.expression !== false
379
- ) {
380
- returnStatements.push(
381
- ...ASTUtils.getNestedReturnStatements(node.expression),
382
- )
383
- }
384
-
385
- if ('test' in node && node.test !== null) {
386
- returnStatements.push(...ASTUtils.getNestedReturnStatements(node.test))
387
- }
388
-
389
- return returnStatements
390
- },
391
- }
@@ -1,97 +0,0 @@
1
- import { TSESTree } from '@typescript-eslint/utils'
2
- import type { ESLintUtils, TSESLint } from '@typescript-eslint/utils'
3
-
4
- type Create = Parameters<
5
- ReturnType<typeof ESLintUtils.RuleCreator>
6
- >[0]['create']
7
-
8
- type Context = Parameters<Create>[0]
9
- type Options = Parameters<Create>[1]
10
- type Helpers = {
11
- isSpecificTanstackQueryImport: (
12
- node: TSESTree.Identifier,
13
- source: string,
14
- ) => boolean
15
- isTanstackQueryImport: (node: TSESTree.Identifier) => boolean
16
- }
17
-
18
- type EnhancedCreate = (
19
- context: Context,
20
- options: Options,
21
- helpers: Helpers,
22
- ) => ReturnType<Create>
23
-
24
- export function detectTanstackQueryImports(create: EnhancedCreate): Create {
25
- return (context, optionsWithDefault) => {
26
- const tanstackQueryImportSpecifiers: Array<TSESTree.ImportClause> = []
27
-
28
- const helpers: Helpers = {
29
- isSpecificTanstackQueryImport(node, source) {
30
- return !!tanstackQueryImportSpecifiers.find((specifier) => {
31
- if (
32
- specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier &&
33
- specifier.parent.type ===
34
- TSESTree.AST_NODE_TYPES.ImportDeclaration &&
35
- specifier.parent.source.value === source
36
- ) {
37
- return node.name === specifier.local.name
38
- }
39
-
40
- return false
41
- })
42
- },
43
- isTanstackQueryImport(node) {
44
- return !!tanstackQueryImportSpecifiers.find((specifier) => {
45
- if (specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier) {
46
- return node.name === specifier.local.name
47
- }
48
-
49
- return false
50
- })
51
- },
52
- }
53
-
54
- const detectionInstructions: TSESLint.RuleListener = {
55
- ImportDeclaration(node) {
56
- if (
57
- node.specifiers.length > 0 &&
58
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
59
- (node.importKind === 'value' || node.importKind === undefined) &&
60
- node.source.value.startsWith('@tanstack/') &&
61
- node.source.value.endsWith('-query')
62
- ) {
63
- tanstackQueryImportSpecifiers.push(...node.specifiers)
64
- }
65
- },
66
- }
67
-
68
- // Call original rule definition
69
- const ruleInstructions = create(context, optionsWithDefault, helpers)
70
- const enhancedRuleInstructions: TSESLint.RuleListener = {}
71
-
72
- const allKeys = new Set(
73
- Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions)),
74
- )
75
-
76
- // Iterate over ALL instructions keys so we can override original rule instructions
77
- // to prevent their execution if conditions to report errors are not met.
78
- allKeys.forEach((instruction) => {
79
- enhancedRuleInstructions[instruction] = (node) => {
80
- if (instruction in detectionInstructions) {
81
- detectionInstructions[instruction]?.(node)
82
- }
83
-
84
- const ruleInstruction = ruleInstructions[instruction]
85
-
86
- // TODO: canReportErrors()
87
- if (ruleInstruction) {
88
- return ruleInstruction(node)
89
- }
90
-
91
- return undefined
92
- }
93
- })
94
-
95
- return enhancedRuleInstructions
96
- }
97
- }
@@ -1,2 +0,0 @@
1
- export const getDocsUrl = (ruleName: string): string =>
2
- `https://tanstack.com/query/latest/docs/eslint/${ruleName}`
@@ -1,3 +0,0 @@
1
- export function uniqueBy<T>(arr: Array<T>, fn: (x: T) => unknown): Array<T> {
2
- return arr.filter((x, i, a) => a.findIndex((y) => fn(x) === fn(y)) === i)
3
- }