@tanstack/eslint-plugin-query 5.95.1 → 5.96.0

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.
@@ -225,7 +225,9 @@ export declare const name_alias_4 = "no-unstable-deps";
225
225
 
226
226
  export declare const name_alias_5 = "no-void-query-fn";
227
227
 
228
- export declare const name_alias_6 = "stable-query-client";
228
+ export declare const name_alias_6 = "prefer-query-options";
229
+
230
+ export declare const name_alias_7 = "stable-query-client";
229
231
 
230
232
  export declare const NoRestDestructuringUtils: {
231
233
  isObjectRestDestructuring(node: TSESTree.Node): boolean;
@@ -243,13 +245,26 @@ declare const plugin: {
243
245
  recommended: {
244
246
  plugins: string[];
245
247
  rules: {
246
- '@tanstack/query/exhaustive-deps': "error";
247
- '@tanstack/query/no-rest-destructuring': "warn";
248
- '@tanstack/query/stable-query-client': "error";
249
- '@tanstack/query/no-unstable-deps': "error";
250
- '@tanstack/query/infinite-query-property-order': "error";
251
- '@tanstack/query/no-void-query-fn': "error";
252
- '@tanstack/query/mutation-property-order': "error";
248
+ readonly '@tanstack/query/exhaustive-deps': "error";
249
+ readonly '@tanstack/query/no-rest-destructuring': "warn";
250
+ readonly '@tanstack/query/stable-query-client': "error";
251
+ readonly '@tanstack/query/no-unstable-deps': "error";
252
+ readonly '@tanstack/query/infinite-query-property-order': "error";
253
+ readonly '@tanstack/query/no-void-query-fn': "error";
254
+ readonly '@tanstack/query/mutation-property-order': "error";
255
+ };
256
+ };
257
+ recommendedStrict: {
258
+ plugins: string[];
259
+ rules: {
260
+ readonly '@tanstack/query/prefer-query-options': "error";
261
+ readonly '@tanstack/query/exhaustive-deps': "error";
262
+ readonly '@tanstack/query/no-rest-destructuring': "warn";
263
+ readonly '@tanstack/query/stable-query-client': "error";
264
+ readonly '@tanstack/query/no-unstable-deps': "error";
265
+ readonly '@tanstack/query/infinite-query-property-order': "error";
266
+ readonly '@tanstack/query/no-void-query-fn': "error";
267
+ readonly '@tanstack/query/mutation-property-order': "error";
253
268
  };
254
269
  };
255
270
  'flat/recommended': {
@@ -258,13 +273,29 @@ declare const plugin: {
258
273
  '@tanstack/query': {};
259
274
  };
260
275
  rules: {
261
- '@tanstack/query/exhaustive-deps': "error";
262
- '@tanstack/query/no-rest-destructuring': "warn";
263
- '@tanstack/query/stable-query-client': "error";
264
- '@tanstack/query/no-unstable-deps': "error";
265
- '@tanstack/query/infinite-query-property-order': "error";
266
- '@tanstack/query/no-void-query-fn': "error";
267
- '@tanstack/query/mutation-property-order': "error";
276
+ readonly '@tanstack/query/exhaustive-deps': "error";
277
+ readonly '@tanstack/query/no-rest-destructuring': "warn";
278
+ readonly '@tanstack/query/stable-query-client': "error";
279
+ readonly '@tanstack/query/no-unstable-deps': "error";
280
+ readonly '@tanstack/query/infinite-query-property-order': "error";
281
+ readonly '@tanstack/query/no-void-query-fn': "error";
282
+ readonly '@tanstack/query/mutation-property-order': "error";
283
+ };
284
+ }[];
285
+ 'flat/recommended-strict': {
286
+ name: string;
287
+ plugins: {
288
+ '@tanstack/query': {};
289
+ };
290
+ rules: {
291
+ readonly '@tanstack/query/prefer-query-options': "error";
292
+ readonly '@tanstack/query/exhaustive-deps': "error";
293
+ readonly '@tanstack/query/no-rest-destructuring': "warn";
294
+ readonly '@tanstack/query/stable-query-client': "error";
295
+ readonly '@tanstack/query/no-unstable-deps': "error";
296
+ readonly '@tanstack/query/infinite-query-property-order': "error";
297
+ readonly '@tanstack/query/no-void-query-fn': "error";
298
+ readonly '@tanstack/query/mutation-property-order': "error";
268
299
  };
269
300
  }[];
270
301
  };
@@ -277,7 +308,9 @@ declare interface Plugin_2 extends Omit<ESLint.Plugin, 'rules'> {
277
308
  rules: Record<RuleKey, RuleModule<any, any, any>>;
278
309
  configs: {
279
310
  recommended: ESLint.ConfigData;
311
+ recommendedStrict: ESLint.ConfigData;
280
312
  'flat/recommended': Array<Linter.Config>;
313
+ 'flat/recommended-strict': Array<Linter.Config>;
281
314
  };
282
315
  }
283
316
  export { Plugin_2 as Plugin }
@@ -312,6 +345,10 @@ export declare const rule_alias_6: ESLintUtils.RuleModule<string, readonly unkno
312
345
  name: string;
313
346
  };
314
347
 
348
+ export declare const rule_alias_7: ESLintUtils.RuleModule<string, readonly unknown[], ExtraRuleDocs, ESLintUtils.RuleListener> & {
349
+ name: string;
350
+ };
351
+
315
352
  declare type RuleKey = keyof typeof rules;
316
353
 
317
354
  export declare const rules: Record<string, ESLintUtils.RuleModule<string, ReadonlyArray<unknown>, ExtraRuleDocs, ESLintUtils.RuleListener>>;
@@ -17,11 +17,11 @@ var ASTUtils = {
17
17
  isIdentifier(node) {
18
18
  return node.type === AST_NODE_TYPES.Identifier;
19
19
  },
20
- isIdentifierWithName(node, name8) {
21
- return ASTUtils.isIdentifier(node) && node.name === name8;
20
+ isIdentifierWithName(node, name9) {
21
+ return ASTUtils.isIdentifier(node) && node.name === name9;
22
22
  },
23
- isIdentifierWithOneOfNames(node, name8) {
24
- return ASTUtils.isIdentifier(node) && name8.includes(node.name);
23
+ isIdentifierWithOneOfNames(node, name9) {
24
+ return ASTUtils.isIdentifier(node) && name9.includes(node.name);
25
25
  },
26
26
  isProperty(node) {
27
27
  return node.type === AST_NODE_TYPES.Property;
@@ -391,8 +391,8 @@ var ExhaustiveDepsUtils = {
391
391
  const roots = /* @__PURE__ */ new Set();
392
392
  const paths = /* @__PURE__ */ new Set();
393
393
  const visitorKeys = sourceCode.visitorKeys;
394
- function addRoot(name8) {
395
- const cleaned = ExhaustiveDepsUtils.normalizeChain(name8);
394
+ function addRoot(name9) {
395
+ const cleaned = ExhaustiveDepsUtils.normalizeChain(name9);
396
396
  roots.add(cleaned);
397
397
  paths.add(cleaned);
398
398
  }
@@ -1318,6 +1318,257 @@ var rule7 = createPropertyOrderRule(
1318
1318
  sortRules2
1319
1319
  );
1320
1320
 
1321
+ // src/rules/prefer-query-options/prefer-query-options.rule.ts
1322
+ import { AST_NODE_TYPES as AST_NODE_TYPES9, ESLintUtils as ESLintUtils7 } from "@typescript-eslint/utils";
1323
+ var name8 = "prefer-query-options";
1324
+ var queryHooks2 = [
1325
+ "useQuery",
1326
+ "useInfiniteQuery",
1327
+ "useSuspenseQuery",
1328
+ "useSuspenseInfiniteQuery",
1329
+ "usePrefetchQuery",
1330
+ "usePrefetchInfiniteQuery"
1331
+ ];
1332
+ var queriesHooks = ["useQueries", "useSuspenseQueries"];
1333
+ var filterHooks = ["useIsFetching"];
1334
+ var queryClientOptionMethods = [
1335
+ "fetchQuery",
1336
+ "prefetchQuery",
1337
+ "fetchInfiniteQuery",
1338
+ "prefetchInfiniteQuery",
1339
+ "ensureQueryData",
1340
+ "ensureInfiniteQueryData"
1341
+ ];
1342
+ var queryClientQueryKeyMethods = [
1343
+ "getQueryData",
1344
+ "setQueryData",
1345
+ "getQueryState",
1346
+ "setQueryDefaults",
1347
+ "getQueryDefaults"
1348
+ ];
1349
+ var queryClientFilterMethods = [
1350
+ "invalidateQueries",
1351
+ "cancelQueries",
1352
+ "refetchQueries",
1353
+ "removeQueries",
1354
+ "resetQueries",
1355
+ "isFetching",
1356
+ "getQueriesData",
1357
+ "setQueriesData"
1358
+ ];
1359
+ var queryOptionsBuilders = ["queryOptions", "infiniteQueryOptions"];
1360
+ var createRule7 = ESLintUtils7.RuleCreator(getDocsUrl);
1361
+ var rule8 = createRule7({
1362
+ name: name8,
1363
+ meta: {
1364
+ type: "problem",
1365
+ docs: {
1366
+ description: "Prefer using queryOptions() to co-locate queryKey and queryFn",
1367
+ recommended: "strict"
1368
+ },
1369
+ messages: {
1370
+ preferQueryOptions: "Prefer using queryOptions() or infiniteQueryOptions() to co-locate queryKey and queryFn.",
1371
+ preferQueryOptionsQueryKey: "Prefer referencing a queryKey from a queryOptions() result instead of typing it manually."
1372
+ },
1373
+ schema: []
1374
+ },
1375
+ defaultOptions: [],
1376
+ create: detectTanstackQueryImports((context, _, helpers) => {
1377
+ function reportInlineQueryOptions(node) {
1378
+ if (ASTUtils.isObjectExpression(node) && hasInlineQueryOptions(node)) {
1379
+ context.report({
1380
+ node,
1381
+ messageId: "preferQueryOptions"
1382
+ });
1383
+ }
1384
+ }
1385
+ function reportInlineFilterQueryKey(node) {
1386
+ if (ASTUtils.isObjectExpression(node) && hasInlineFilterQueryKey(node)) {
1387
+ context.report({
1388
+ node,
1389
+ messageId: "preferQueryOptionsQueryKey"
1390
+ });
1391
+ }
1392
+ }
1393
+ return {
1394
+ CallExpression: (node) => {
1395
+ if (ASTUtils.isIdentifier(node.callee)) {
1396
+ const importedName = getTanstackImportName(
1397
+ context,
1398
+ helpers,
1399
+ node.callee
1400
+ );
1401
+ if (importedName === null) {
1402
+ return;
1403
+ }
1404
+ if (queryOptionsBuilders.includes(importedName)) {
1405
+ return;
1406
+ }
1407
+ const options2 = node.arguments[0];
1408
+ if (options2 === void 0) {
1409
+ return;
1410
+ }
1411
+ if (queryHooks2.includes(importedName)) {
1412
+ reportInlineQueryOptions(options2);
1413
+ return;
1414
+ }
1415
+ if (queriesHooks.includes(importedName) && ASTUtils.isObjectExpression(options2)) {
1416
+ const queries = ASTUtils.findPropertyWithIdentifierKey(
1417
+ options2.properties,
1418
+ "queries"
1419
+ )?.value;
1420
+ if (queries !== void 0) {
1421
+ getQueryObjects(queries).forEach((query) => {
1422
+ reportInlineQueryOptions(query);
1423
+ });
1424
+ }
1425
+ return;
1426
+ }
1427
+ if (filterHooks.includes(importedName)) {
1428
+ reportInlineFilterQueryKey(options2);
1429
+ }
1430
+ return;
1431
+ }
1432
+ if (node.callee.type !== AST_NODE_TYPES9.MemberExpression || !ASTUtils.isIdentifier(node.callee.property) || !isTanstackQueryClient(node.callee.object, context, helpers)) {
1433
+ return;
1434
+ }
1435
+ const method = node.callee.property.name;
1436
+ const options = node.arguments[0];
1437
+ if (options === void 0) {
1438
+ return;
1439
+ }
1440
+ if (queryClientOptionMethods.includes(method)) {
1441
+ reportInlineQueryOptions(options);
1442
+ return;
1443
+ }
1444
+ if (queryClientQueryKeyMethods.includes(method) && isInlineArrayExpression(options)) {
1445
+ context.report({
1446
+ node: options,
1447
+ messageId: "preferQueryOptionsQueryKey"
1448
+ });
1449
+ return;
1450
+ }
1451
+ if (queryClientFilterMethods.includes(method)) {
1452
+ reportInlineFilterQueryKey(options);
1453
+ }
1454
+ }
1455
+ };
1456
+ })
1457
+ });
1458
+ function hasInlineQueryOptions(node) {
1459
+ return ASTUtils.findPropertyWithIdentifierKey(node.properties, "queryKey") !== void 0 || ASTUtils.findPropertyWithIdentifierKey(node.properties, "queryFn") !== void 0;
1460
+ }
1461
+ function hasInlineFilterQueryKey(node) {
1462
+ const queryKey = ASTUtils.findPropertyWithIdentifierKey(
1463
+ node.properties,
1464
+ "queryKey"
1465
+ )?.value;
1466
+ return queryKey !== void 0 && isInlineArrayExpression(queryKey);
1467
+ }
1468
+ function isInlineArrayExpression(node) {
1469
+ return unwrapTypeAssertions(node).type === AST_NODE_TYPES9.ArrayExpression;
1470
+ }
1471
+ function getReturnedObjectExpressions(node) {
1472
+ if (ASTUtils.isObjectExpression(node)) {
1473
+ return [node];
1474
+ }
1475
+ if (node.type === AST_NODE_TYPES9.ArrowFunctionExpression || node.type === AST_NODE_TYPES9.FunctionExpression) {
1476
+ return getReturnedObjectExpressions(node.body);
1477
+ }
1478
+ if (node.type === AST_NODE_TYPES9.BlockStatement) {
1479
+ return node.body.flatMap((statement) => {
1480
+ if (statement.type === AST_NODE_TYPES9.ReturnStatement && statement.argument !== null) {
1481
+ return getReturnedObjectExpressions(statement.argument);
1482
+ }
1483
+ return [];
1484
+ });
1485
+ }
1486
+ if (node.type === AST_NODE_TYPES9.ConditionalExpression) {
1487
+ return [
1488
+ ...getReturnedObjectExpressions(node.consequent),
1489
+ ...getReturnedObjectExpressions(node.alternate)
1490
+ ];
1491
+ }
1492
+ if (node.type === AST_NODE_TYPES9.LogicalExpression) {
1493
+ return [
1494
+ ...getReturnedObjectExpressions(node.left),
1495
+ ...getReturnedObjectExpressions(node.right)
1496
+ ];
1497
+ }
1498
+ if (node.type === AST_NODE_TYPES9.SequenceExpression) {
1499
+ return node.expressions.flatMap(
1500
+ (expression) => getReturnedObjectExpressions(expression)
1501
+ );
1502
+ }
1503
+ return [];
1504
+ }
1505
+ function getQueryObjects(node) {
1506
+ if (node.type === AST_NODE_TYPES9.ArrayExpression) {
1507
+ return node.elements.flatMap((element) => {
1508
+ if (element !== null && ASTUtils.isObjectExpression(element)) {
1509
+ return [element];
1510
+ }
1511
+ return [];
1512
+ });
1513
+ }
1514
+ if (node.type === AST_NODE_TYPES9.CallExpression && node.callee.type === AST_NODE_TYPES9.MemberExpression && ASTUtils.isIdentifierWithName(node.callee.property, "map")) {
1515
+ const mapper = node.arguments[0];
1516
+ if (mapper?.type === AST_NODE_TYPES9.ArrowFunctionExpression || mapper?.type === AST_NODE_TYPES9.FunctionExpression) {
1517
+ return getReturnedObjectExpressions(mapper);
1518
+ }
1519
+ }
1520
+ return [];
1521
+ }
1522
+ function isTanstackQueryClient(node, context, helpers) {
1523
+ const source = resolveQueryClientSource(node, context);
1524
+ if (source.type === AST_NODE_TYPES9.CallExpression && ASTUtils.isIdentifier(source.callee)) {
1525
+ return getTanstackImportName(context, helpers, source.callee) === "useQueryClient";
1526
+ }
1527
+ if (source.type === AST_NODE_TYPES9.NewExpression && ASTUtils.isIdentifier(source.callee)) {
1528
+ return getTanstackImportName(context, helpers, source.callee) === "QueryClient";
1529
+ }
1530
+ return false;
1531
+ }
1532
+ function getTanstackImportName(context, helpers, node) {
1533
+ if (!helpers.isTanstackQueryImport(node)) {
1534
+ return null;
1535
+ }
1536
+ const definition = context.sourceCode.getScope(node).references.find((reference) => reference.identifier === node)?.resolved?.defs[0]?.node;
1537
+ if (definition?.type !== AST_NODE_TYPES9.ImportSpecifier || definition.imported.type !== AST_NODE_TYPES9.Identifier) {
1538
+ return null;
1539
+ }
1540
+ return definition.imported.name;
1541
+ }
1542
+ function resolveQueryClientSource(node, context) {
1543
+ const visitedNodes = /* @__PURE__ */ new Set();
1544
+ while (!visitedNodes.has(node)) {
1545
+ visitedNodes.add(node);
1546
+ if (node.type === AST_NODE_TYPES9.ChainExpression) {
1547
+ node = node.expression;
1548
+ continue;
1549
+ }
1550
+ node = unwrapTypeAssertions(node);
1551
+ if (node.type !== AST_NODE_TYPES9.Identifier) {
1552
+ return node;
1553
+ }
1554
+ const expression = ASTUtils.getReferencedExpressionByIdentifier({
1555
+ context,
1556
+ node
1557
+ });
1558
+ if (expression === null) {
1559
+ return node;
1560
+ }
1561
+ node = expression;
1562
+ }
1563
+ return node;
1564
+ }
1565
+ function unwrapTypeAssertions(node) {
1566
+ while (node.type === AST_NODE_TYPES9.TSAsExpression || node.type === AST_NODE_TYPES9.TSSatisfiesExpression || node.type === AST_NODE_TYPES9.TSTypeAssertion) {
1567
+ node = node.expression;
1568
+ }
1569
+ return node;
1570
+ }
1571
+
1321
1572
  // src/rules.ts
1322
1573
  var rules = {
1323
1574
  [name]: rule,
@@ -1326,10 +1577,11 @@ var rules = {
1326
1577
  [name4]: rule4,
1327
1578
  [name5]: rule5,
1328
1579
  [name6]: rule6,
1329
- [name7]: rule7
1580
+ [name7]: rule7,
1581
+ [name8]: rule8
1330
1582
  };
1331
1583
 
1332
1584
  export {
1333
1585
  rules
1334
1586
  };
1335
- //# sourceMappingURL=chunk-XH4ABCYA.js.map
1587
+ //# sourceMappingURL=chunk-J3JFOQ5Q.js.map