@tanstack/eslint-plugin-query 5.0.0-alpha.6 → 5.0.0-alpha.74
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.
- package/build/lib/index.cjs +465 -0
- package/build/lib/index.cjs.map +1 -0
- package/build/lib/index.d.cts +14 -0
- package/build/lib/index.d.ts +14 -2
- package/build/lib/index.js +437 -6
- package/build/lib/index.js.map +1 -0
- package/package.json +30 -21
- package/src/configs/index.test.ts +18 -0
- package/src/configs/index.ts +22 -0
- package/src/index.ts +2 -0
- package/src/rules/exhaustive-deps/exhaustive-deps.rule.ts +154 -0
- package/src/rules/exhaustive-deps/exhaustive-deps.test.ts +721 -0
- package/src/rules/exhaustive-deps/exhaustive-deps.utils.ts +41 -0
- package/src/rules/index.ts +5 -0
- package/src/utils/ast-utils.ts +318 -0
- package/src/utils/create-rule.ts +20 -0
- package/src/utils/detect-react-query-imports.ts +75 -0
- package/src/utils/object-utils.ts +5 -0
- package/src/utils/test-utils.ts +5 -0
- package/src/utils/unique-by.ts +3 -0
- package/build/.tsbuildinfo +0 -1
- package/build/lib/configs/index.d.ts +0 -6
- package/build/lib/configs/index.test.d.ts +0 -1
- package/build/lib/rules/exhaustive-deps/exhaustive-deps.rule.d.ts +0 -3
- package/build/lib/rules/exhaustive-deps/exhaustive-deps.test.d.ts +0 -1
- package/build/lib/rules/index.d.ts +0 -3
- package/build/lib/utils/ast-utils.d.ts +0 -31
- package/build/lib/utils/create-rule.d.ts +0 -7
- package/build/lib/utils/detect-react-query-imports.d.ts +0 -10
- package/build/lib/utils/object-utils.d.ts +0 -1
- package/build/lib/utils/test-utils.d.ts +0 -1
- package/build/lib/utils/unique-by.d.ts +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { TSESLint } from '@typescript-eslint/utils'
|
|
2
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils'
|
|
3
|
+
import { ASTUtils } from '../../utils/ast-utils'
|
|
4
|
+
|
|
5
|
+
export const ExhaustiveDepsUtils = {
|
|
6
|
+
isRelevantReference(params: {
|
|
7
|
+
context: Readonly<TSESLint.RuleContext<string, readonly unknown[]>>
|
|
8
|
+
reference: TSESLint.Scope.Reference
|
|
9
|
+
scopeManager: TSESLint.Scope.ScopeManager
|
|
10
|
+
}) {
|
|
11
|
+
const { reference, scopeManager, context } = params
|
|
12
|
+
const component = ASTUtils.getFunctionAncestor(context)
|
|
13
|
+
|
|
14
|
+
if (
|
|
15
|
+
component !== undefined &&
|
|
16
|
+
!ASTUtils.isDeclaredInNode({
|
|
17
|
+
scopeManager,
|
|
18
|
+
reference,
|
|
19
|
+
functionNode: component,
|
|
20
|
+
})
|
|
21
|
+
) {
|
|
22
|
+
return false
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
reference.identifier.name !== 'undefined' &&
|
|
27
|
+
reference.identifier.parent?.type !== AST_NODE_TYPES.NewExpression &&
|
|
28
|
+
!ExhaustiveDepsUtils.isQueryClientReference(reference)
|
|
29
|
+
)
|
|
30
|
+
},
|
|
31
|
+
isQueryClientReference(reference: TSESLint.Scope.Reference) {
|
|
32
|
+
const declarator = reference.resolved?.defs[0]?.node
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
declarator?.type === AST_NODE_TYPES.VariableDeclarator &&
|
|
36
|
+
declarator.init?.type === AST_NODE_TYPES.CallExpression &&
|
|
37
|
+
declarator.init.callee.type === AST_NODE_TYPES.Identifier &&
|
|
38
|
+
declarator.init.callee.name === 'useQueryClient'
|
|
39
|
+
)
|
|
40
|
+
},
|
|
41
|
+
}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import type { TSESLint, TSESTree } from '@typescript-eslint/utils'
|
|
2
|
+
import type TSESLintScopeManager from '@typescript-eslint/scope-manager'
|
|
3
|
+
import { AST_NODE_TYPES } from '@typescript-eslint/utils'
|
|
4
|
+
import type { RuleContext } from '@typescript-eslint/utils/dist/ts-eslint'
|
|
5
|
+
import { uniqueBy } from './unique-by'
|
|
6
|
+
|
|
7
|
+
export const ASTUtils = {
|
|
8
|
+
isNodeOfOneOf<T extends AST_NODE_TYPES>(
|
|
9
|
+
node: TSESTree.Node,
|
|
10
|
+
types: readonly T[],
|
|
11
|
+
): node is TSESTree.Node & { type: T } {
|
|
12
|
+
return types.includes(node.type as T)
|
|
13
|
+
},
|
|
14
|
+
isIdentifier(node: TSESTree.Node): node is TSESTree.Identifier {
|
|
15
|
+
return node.type === AST_NODE_TYPES.Identifier
|
|
16
|
+
},
|
|
17
|
+
isIdentifierWithName(
|
|
18
|
+
node: TSESTree.Node,
|
|
19
|
+
name: string,
|
|
20
|
+
): node is TSESTree.Identifier {
|
|
21
|
+
return ASTUtils.isIdentifier(node) && node.name === name
|
|
22
|
+
},
|
|
23
|
+
isIdentifierWithOneOfNames<T extends string[]>(
|
|
24
|
+
node: TSESTree.Node,
|
|
25
|
+
name: T,
|
|
26
|
+
): node is TSESTree.Identifier & { name: T[number] } {
|
|
27
|
+
return ASTUtils.isIdentifier(node) && name.includes(node.name)
|
|
28
|
+
},
|
|
29
|
+
isProperty(node: TSESTree.Node): node is TSESTree.Property {
|
|
30
|
+
return node.type === AST_NODE_TYPES.Property
|
|
31
|
+
},
|
|
32
|
+
isObjectExpression(node: TSESTree.Node): node is TSESTree.ObjectExpression {
|
|
33
|
+
return node.type === AST_NODE_TYPES.ObjectExpression
|
|
34
|
+
},
|
|
35
|
+
isPropertyWithIdentifierKey(
|
|
36
|
+
node: TSESTree.Node,
|
|
37
|
+
key: string,
|
|
38
|
+
): node is TSESTree.Property {
|
|
39
|
+
return (
|
|
40
|
+
ASTUtils.isProperty(node) && ASTUtils.isIdentifierWithName(node.key, key)
|
|
41
|
+
)
|
|
42
|
+
},
|
|
43
|
+
findPropertyWithIdentifierKey(
|
|
44
|
+
properties: TSESTree.ObjectLiteralElement[],
|
|
45
|
+
key: string,
|
|
46
|
+
): TSESTree.Property | undefined {
|
|
47
|
+
return properties.find((x) =>
|
|
48
|
+
ASTUtils.isPropertyWithIdentifierKey(x, key),
|
|
49
|
+
) as TSESTree.Property | undefined
|
|
50
|
+
},
|
|
51
|
+
getNestedIdentifiers(node: TSESTree.Node): TSESTree.Identifier[] {
|
|
52
|
+
const identifiers: TSESTree.Identifier[] = []
|
|
53
|
+
|
|
54
|
+
if (ASTUtils.isIdentifier(node)) {
|
|
55
|
+
identifiers.push(node)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if ('arguments' in node) {
|
|
59
|
+
node.arguments.forEach((x) => {
|
|
60
|
+
identifiers.push(...ASTUtils.getNestedIdentifiers(x))
|
|
61
|
+
})
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if ('elements' in node) {
|
|
65
|
+
node.elements.forEach((x) => {
|
|
66
|
+
if (x !== null) {
|
|
67
|
+
identifiers.push(...ASTUtils.getNestedIdentifiers(x))
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if ('properties' in node) {
|
|
73
|
+
node.properties.forEach((x) => {
|
|
74
|
+
identifiers.push(...ASTUtils.getNestedIdentifiers(x))
|
|
75
|
+
})
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if ('expressions' in node) {
|
|
79
|
+
node.expressions.forEach((x) => {
|
|
80
|
+
identifiers.push(...ASTUtils.getNestedIdentifiers(x))
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (node.type === AST_NODE_TYPES.Property) {
|
|
85
|
+
identifiers.push(...ASTUtils.getNestedIdentifiers(node.value))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (node.type === AST_NODE_TYPES.SpreadElement) {
|
|
89
|
+
identifiers.push(...ASTUtils.getNestedIdentifiers(node.argument))
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (node.type === AST_NODE_TYPES.MemberExpression) {
|
|
93
|
+
identifiers.push(...ASTUtils.getNestedIdentifiers(node.object))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (node.type === AST_NODE_TYPES.UnaryExpression) {
|
|
97
|
+
identifiers.push(...ASTUtils.getNestedIdentifiers(node.argument))
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (node.type === AST_NODE_TYPES.ChainExpression) {
|
|
101
|
+
identifiers.push(...ASTUtils.getNestedIdentifiers(node.expression))
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (node.type === AST_NODE_TYPES.TSNonNullExpression) {
|
|
105
|
+
identifiers.push(...ASTUtils.getNestedIdentifiers(node.expression))
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return identifiers
|
|
109
|
+
},
|
|
110
|
+
isAncestorIsCallee(identifier: TSESTree.Node) {
|
|
111
|
+
let previousNode = identifier
|
|
112
|
+
let currentNode = identifier.parent
|
|
113
|
+
|
|
114
|
+
while (currentNode !== undefined) {
|
|
115
|
+
if (
|
|
116
|
+
currentNode.type === AST_NODE_TYPES.CallExpression &&
|
|
117
|
+
currentNode.callee === previousNode
|
|
118
|
+
) {
|
|
119
|
+
return true
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (currentNode.type !== AST_NODE_TYPES.MemberExpression) {
|
|
123
|
+
return false
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
previousNode = currentNode
|
|
127
|
+
currentNode = currentNode.parent
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return false
|
|
131
|
+
},
|
|
132
|
+
traverseUpOnly(
|
|
133
|
+
identifier: TSESTree.Node,
|
|
134
|
+
allowedNodeTypes: AST_NODE_TYPES[],
|
|
135
|
+
): TSESTree.Node {
|
|
136
|
+
const parent = identifier.parent
|
|
137
|
+
|
|
138
|
+
if (parent !== undefined && allowedNodeTypes.includes(parent.type)) {
|
|
139
|
+
return ASTUtils.traverseUpOnly(parent, allowedNodeTypes)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return identifier
|
|
143
|
+
},
|
|
144
|
+
isDeclaredInNode(params: {
|
|
145
|
+
functionNode: TSESTree.Node
|
|
146
|
+
reference: TSESLintScopeManager.Reference
|
|
147
|
+
scopeManager: TSESLint.Scope.ScopeManager
|
|
148
|
+
}) {
|
|
149
|
+
const { functionNode, reference, scopeManager } = params
|
|
150
|
+
const scope = scopeManager.acquire(functionNode)
|
|
151
|
+
|
|
152
|
+
if (scope === null) {
|
|
153
|
+
return false
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return scope.set.has(reference.identifier.name)
|
|
157
|
+
},
|
|
158
|
+
getExternalRefs(params: {
|
|
159
|
+
scopeManager: TSESLint.Scope.ScopeManager
|
|
160
|
+
sourceCode: Readonly<TSESLint.SourceCode>
|
|
161
|
+
node: TSESTree.Node
|
|
162
|
+
}): TSESLint.Scope.Reference[] {
|
|
163
|
+
const { scopeManager, sourceCode, node } = params
|
|
164
|
+
const scope = scopeManager.acquire(node)
|
|
165
|
+
|
|
166
|
+
if (scope === null) {
|
|
167
|
+
return []
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const references = scope.references
|
|
171
|
+
.filter((x) => x.isRead() && !scope.set.has(x.identifier.name))
|
|
172
|
+
.map((x) => {
|
|
173
|
+
const referenceNode = ASTUtils.traverseUpOnly(x.identifier, [
|
|
174
|
+
AST_NODE_TYPES.MemberExpression,
|
|
175
|
+
AST_NODE_TYPES.Identifier,
|
|
176
|
+
])
|
|
177
|
+
|
|
178
|
+
return {
|
|
179
|
+
variable: x,
|
|
180
|
+
node: referenceNode,
|
|
181
|
+
text: sourceCode.getText(referenceNode),
|
|
182
|
+
}
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
const localRefIds = new Set(
|
|
186
|
+
[...scope.set.values()].map((x) => sourceCode.getText(x.identifiers[0])),
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
const externalRefs = references.filter(
|
|
190
|
+
(x) => x.variable.resolved === null || !localRefIds.has(x.text),
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
return uniqueBy(externalRefs, (x) => x.text).map((x) => x.variable)
|
|
194
|
+
},
|
|
195
|
+
mapKeyNodeToText(
|
|
196
|
+
node: TSESTree.Node,
|
|
197
|
+
sourceCode: Readonly<TSESLint.SourceCode>,
|
|
198
|
+
) {
|
|
199
|
+
return sourceCode.getText(
|
|
200
|
+
ASTUtils.traverseUpOnly(node, [
|
|
201
|
+
AST_NODE_TYPES.MemberExpression,
|
|
202
|
+
AST_NODE_TYPES.Identifier,
|
|
203
|
+
]),
|
|
204
|
+
)
|
|
205
|
+
},
|
|
206
|
+
isValidReactComponentOrHookName(identifier: TSESTree.Identifier | null) {
|
|
207
|
+
return identifier !== null && /^(use|[A-Z])/.test(identifier.name)
|
|
208
|
+
},
|
|
209
|
+
getFunctionAncestor(
|
|
210
|
+
context: Readonly<RuleContext<string, readonly unknown[]>>,
|
|
211
|
+
) {
|
|
212
|
+
return context.getAncestors().find((x) => {
|
|
213
|
+
if (x.type === AST_NODE_TYPES.FunctionDeclaration) {
|
|
214
|
+
return true
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
x.parent?.type === AST_NODE_TYPES.VariableDeclarator &&
|
|
219
|
+
x.parent.id.type === AST_NODE_TYPES.Identifier &&
|
|
220
|
+
ASTUtils.isNodeOfOneOf(x, [
|
|
221
|
+
AST_NODE_TYPES.FunctionDeclaration,
|
|
222
|
+
AST_NODE_TYPES.FunctionExpression,
|
|
223
|
+
AST_NODE_TYPES.ArrowFunctionExpression,
|
|
224
|
+
])
|
|
225
|
+
)
|
|
226
|
+
})
|
|
227
|
+
},
|
|
228
|
+
getReferencedExpressionByIdentifier(params: {
|
|
229
|
+
node: TSESTree.Node
|
|
230
|
+
context: Readonly<RuleContext<string, readonly unknown[]>>
|
|
231
|
+
}) {
|
|
232
|
+
const { node, context } = params
|
|
233
|
+
|
|
234
|
+
const resolvedNode = context
|
|
235
|
+
.getScope()
|
|
236
|
+
.references.find((ref) => ref.identifier === node)?.resolved
|
|
237
|
+
?.defs[0]?.node
|
|
238
|
+
|
|
239
|
+
if (resolvedNode?.type !== AST_NODE_TYPES.VariableDeclarator) {
|
|
240
|
+
return null
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return resolvedNode.init
|
|
244
|
+
},
|
|
245
|
+
getNestedReturnStatements(node: TSESTree.Node): TSESTree.ReturnStatement[] {
|
|
246
|
+
const returnStatements: TSESTree.ReturnStatement[] = []
|
|
247
|
+
|
|
248
|
+
if (node.type === AST_NODE_TYPES.ReturnStatement) {
|
|
249
|
+
returnStatements.push(node)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if ('body' in node && node.body !== undefined && node.body !== null) {
|
|
253
|
+
Array.isArray(node.body)
|
|
254
|
+
? node.body.forEach((x) => {
|
|
255
|
+
returnStatements.push(...ASTUtils.getNestedReturnStatements(x))
|
|
256
|
+
})
|
|
257
|
+
: returnStatements.push(
|
|
258
|
+
...ASTUtils.getNestedReturnStatements(node.body),
|
|
259
|
+
)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if ('consequent' in node) {
|
|
263
|
+
Array.isArray(node.consequent)
|
|
264
|
+
? node.consequent.forEach((x) => {
|
|
265
|
+
returnStatements.push(...ASTUtils.getNestedReturnStatements(x))
|
|
266
|
+
})
|
|
267
|
+
: returnStatements.push(
|
|
268
|
+
...ASTUtils.getNestedReturnStatements(node.consequent),
|
|
269
|
+
)
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if ('alternate' in node && node.alternate !== null) {
|
|
273
|
+
Array.isArray(node.alternate)
|
|
274
|
+
? node.alternate.forEach((x) => {
|
|
275
|
+
returnStatements.push(...ASTUtils.getNestedReturnStatements(x))
|
|
276
|
+
})
|
|
277
|
+
: returnStatements.push(
|
|
278
|
+
...ASTUtils.getNestedReturnStatements(node.alternate),
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if ('cases' in node) {
|
|
283
|
+
node.cases.forEach((x) => {
|
|
284
|
+
returnStatements.push(...ASTUtils.getNestedReturnStatements(x))
|
|
285
|
+
})
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if ('block' in node) {
|
|
289
|
+
returnStatements.push(...ASTUtils.getNestedReturnStatements(node.block))
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if ('handler' in node && node.handler !== null) {
|
|
293
|
+
returnStatements.push(...ASTUtils.getNestedReturnStatements(node.handler))
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if ('finalizer' in node && node.finalizer !== null) {
|
|
297
|
+
returnStatements.push(
|
|
298
|
+
...ASTUtils.getNestedReturnStatements(node.finalizer),
|
|
299
|
+
)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
if (
|
|
303
|
+
'expression' in node &&
|
|
304
|
+
node.expression !== true &&
|
|
305
|
+
node.expression !== false
|
|
306
|
+
) {
|
|
307
|
+
returnStatements.push(
|
|
308
|
+
...ASTUtils.getNestedReturnStatements(node.expression),
|
|
309
|
+
)
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if ('test' in node && node.test !== null) {
|
|
313
|
+
returnStatements.push(...ASTUtils.getNestedReturnStatements(node.test))
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return returnStatements
|
|
317
|
+
},
|
|
318
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils'
|
|
2
|
+
import type { EnhancedCreate } from './detect-react-query-imports'
|
|
3
|
+
import { detectTanstackQueryImports } from './detect-react-query-imports'
|
|
4
|
+
|
|
5
|
+
const getDocsUrl = (ruleName: string): string =>
|
|
6
|
+
`https://tanstack.com/query/v4/docs/eslint/${ruleName}`
|
|
7
|
+
|
|
8
|
+
type EslintRule = Omit<
|
|
9
|
+
Parameters<ReturnType<typeof ESLintUtils.RuleCreator>>[0],
|
|
10
|
+
'create'
|
|
11
|
+
> & {
|
|
12
|
+
create: EnhancedCreate
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function createRule({ create, ...rest }: EslintRule) {
|
|
16
|
+
return ESLintUtils.RuleCreator(getDocsUrl)({
|
|
17
|
+
...rest,
|
|
18
|
+
create: detectTanstackQueryImports(create),
|
|
19
|
+
})
|
|
20
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { ESLintUtils, TSESLint, TSESTree } from '@typescript-eslint/utils'
|
|
2
|
+
|
|
3
|
+
type Create = Parameters<
|
|
4
|
+
ReturnType<typeof ESLintUtils.RuleCreator>
|
|
5
|
+
>[0]['create']
|
|
6
|
+
|
|
7
|
+
type Context = Parameters<Create>[0]
|
|
8
|
+
type Options = Parameters<Create>[1]
|
|
9
|
+
type Helpers = {
|
|
10
|
+
isTanstackQueryImport: (node: TSESTree.Identifier) => boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type EnhancedCreate = (
|
|
14
|
+
context: Context,
|
|
15
|
+
options: Options,
|
|
16
|
+
helpers: Helpers,
|
|
17
|
+
) => ReturnType<Create>
|
|
18
|
+
|
|
19
|
+
export function detectTanstackQueryImports(create: EnhancedCreate): Create {
|
|
20
|
+
return (context, optionsWithDefault) => {
|
|
21
|
+
const tanstackQueryImportSpecifiers: TSESTree.ImportClause[] = []
|
|
22
|
+
|
|
23
|
+
const helpers: Helpers = {
|
|
24
|
+
isTanstackQueryImport(node) {
|
|
25
|
+
return !!tanstackQueryImportSpecifiers.find((specifier) => {
|
|
26
|
+
if (specifier.type === 'ImportSpecifier') {
|
|
27
|
+
return node.name === specifier.local.name
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return false
|
|
31
|
+
})
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const detectionInstructions: TSESLint.RuleListener = {
|
|
36
|
+
ImportDeclaration(node) {
|
|
37
|
+
if (
|
|
38
|
+
node.specifiers.length > 0 &&
|
|
39
|
+
node.importKind === 'value' &&
|
|
40
|
+
node.source.value.startsWith('@tanstack/') &&
|
|
41
|
+
node.source.value.endsWith('-query')
|
|
42
|
+
) {
|
|
43
|
+
tanstackQueryImportSpecifiers.push(...node.specifiers)
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Call original rule definition
|
|
49
|
+
const ruleInstructions = create(context, optionsWithDefault, helpers)
|
|
50
|
+
const enhancedRuleInstructions: TSESLint.RuleListener = {}
|
|
51
|
+
|
|
52
|
+
const allKeys = new Set(
|
|
53
|
+
Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions)),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
// Iterate over ALL instructions keys so we can override original rule instructions
|
|
57
|
+
// to prevent their execution if conditions to report errors are not met.
|
|
58
|
+
allKeys.forEach((instruction) => {
|
|
59
|
+
enhancedRuleInstructions[instruction] = (node) => {
|
|
60
|
+
if (instruction in detectionInstructions) {
|
|
61
|
+
detectionInstructions[instruction]?.(node)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// TODO: canReportErrors()
|
|
65
|
+
if (ruleInstructions[instruction]) {
|
|
66
|
+
return ruleInstructions[instruction]?.(node)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return undefined
|
|
70
|
+
}
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
return enhancedRuleInstructions
|
|
74
|
+
}
|
|
75
|
+
}
|