Skip to content

Commit cde8a93

Browse files
committed
feat(eslint-plugin-query): enhance no-rest-destructuring rule to detect spread operations
1 parent d7f4cb0 commit cde8a93

File tree

2 files changed

+68
-3
lines changed

2 files changed

+68
-3
lines changed

packages/eslint-plugin-query/src/__tests__/no-rest-destructuring.test.ts

+25
Original file line numberDiff line numberDiff line change
@@ -365,5 +365,30 @@ ruleTester.run('no-rest-destructuring', rule, {
365365
`,
366366
errors: [{ messageId: 'objectRestDestructure' }],
367367
},
368+
{
369+
name: 'useQuery result is spread in return statement',
370+
code: normalizeIndent`
371+
import { useQuery } from '@tanstack/react-query'
372+
373+
function Component() {
374+
const query = useQuery()
375+
return { ...query, data: query.data[0] }
376+
}
377+
`,
378+
errors: [{ messageId: 'objectRestDestructure' }],
379+
},
380+
{
381+
name: 'useQuery result is spread in object expression',
382+
code: normalizeIndent`
383+
import { useQuery } from '@tanstack/react-query'
384+
385+
function Component() {
386+
const query = useQuery()
387+
const result = { ...query, data: query.data[0] }
388+
return result
389+
}
390+
`,
391+
errors: [{ messageId: 'objectRestDestructure' }],
392+
},
368393
],
369394
})

packages/eslint-plugin-query/src/rules/no-rest-destructuring/no-rest-destructuring.rule.ts

+43-3
Original file line numberDiff line numberDiff line change
@@ -34,33 +34,46 @@ export const rule = createRule({
3434
defaultOptions: [],
3535

3636
create: detectTanstackQueryImports((context, _, helpers) => {
37+
// Track variables that hold query results
38+
const queryResultVariables = new Set<string>()
39+
3740
return {
3841
CallExpression: (node) => {
3942
if (
4043
!ASTUtils.isIdentifierWithOneOfNames(node.callee, queryHooks) ||
41-
!helpers.isTanstackQueryImport(node.callee) ||
42-
node.parent.type !== AST_NODE_TYPES.VariableDeclarator
44+
node.parent.type !== AST_NODE_TYPES.VariableDeclarator ||
45+
!helpers.isTanstackQueryImport(node.callee)
4346
) {
4447
return
4548
}
4649

4750
const returnValue = node.parent.id
51+
4852
if (
4953
node.callee.name !== 'useQueries' &&
5054
node.callee.name !== 'useSuspenseQueries'
5155
) {
5256
if (NoRestDestructuringUtils.isObjectRestDestructuring(returnValue)) {
53-
context.report({
57+
return context.report({
5458
node: node.parent,
5559
messageId: 'objectRestDestructure',
5660
})
5761
}
62+
63+
if (returnValue.type === AST_NODE_TYPES.Identifier) {
64+
queryResultVariables.add(returnValue.name)
65+
}
66+
5867
return
5968
}
6069

6170
if (returnValue.type !== AST_NODE_TYPES.ArrayPattern) {
71+
if (returnValue.type === AST_NODE_TYPES.Identifier) {
72+
queryResultVariables.add(returnValue.name)
73+
}
6274
return
6375
}
76+
6477
returnValue.elements.forEach((queryResult) => {
6578
if (queryResult === null) {
6679
return
@@ -73,6 +86,33 @@ export const rule = createRule({
7386
}
7487
})
7588
},
89+
90+
// Check for later destructuring of tracked variables
91+
VariableDeclarator: (node) => {
92+
if (
93+
node.init?.type === AST_NODE_TYPES.Identifier &&
94+
queryResultVariables.has(node.init.name) &&
95+
NoRestDestructuringUtils.isObjectRestDestructuring(node.id)
96+
) {
97+
context.report({
98+
node,
99+
messageId: 'objectRestDestructure',
100+
})
101+
}
102+
},
103+
104+
// Check for spread operations in object expressions
105+
SpreadElement: (node) => {
106+
if (
107+
node.argument.type === AST_NODE_TYPES.Identifier &&
108+
queryResultVariables.has(node.argument.name)
109+
) {
110+
context.report({
111+
node,
112+
messageId: 'objectRestDestructure',
113+
})
114+
}
115+
},
76116
}
77117
}),
78118
})

0 commit comments

Comments
 (0)