@tanstack/eslint-plugin-query 5.100.13 → 5.101.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.
@@ -920,12 +920,42 @@ var import_utils7 = require("@typescript-eslint/utils");
920
920
 
921
921
  // src/rules/no-rest-destructuring/no-rest-destructuring.utils.ts
922
922
  var import_utils6 = require("@typescript-eslint/utils");
923
+ var QUERY_RESULT_TYPE_NAMES = /* @__PURE__ */ new Set([
924
+ "UseBaseQueryResult",
925
+ "UseQueryResult",
926
+ "UseSuspenseQueryResult",
927
+ "DefinedUseQueryResult",
928
+ "UseInfiniteQueryResult",
929
+ "UseSuspenseInfiniteQueryResult",
930
+ "DefinedUseInfiniteQueryResult",
931
+ "QueryObserverResult",
932
+ "InfiniteQueryObserverResult"
933
+ ]);
934
+ function isQueryResultType(type) {
935
+ if (type.aliasSymbol && QUERY_RESULT_TYPE_NAMES.has(type.aliasSymbol.name)) {
936
+ return true;
937
+ }
938
+ const symbol = type.getSymbol();
939
+ if (symbol && QUERY_RESULT_TYPE_NAMES.has(symbol.name)) {
940
+ return true;
941
+ }
942
+ return type.isUnion() && type.types.some(isQueryResultType);
943
+ }
923
944
  var NoRestDestructuringUtils = {
924
945
  isObjectRestDestructuring(node) {
925
946
  if (node.type !== import_utils6.AST_NODE_TYPES.ObjectPattern) {
926
947
  return false;
927
948
  }
928
949
  return node.properties.some((p) => p.type === import_utils6.AST_NODE_TYPES.RestElement);
950
+ },
951
+ isQueryResultCall(node, parserServices) {
952
+ if (!(parserServices == null ? void 0 : parserServices.program) || !parserServices.esTreeNodeToTSNodeMap) {
953
+ return false;
954
+ }
955
+ const checker = parserServices.program.getTypeChecker();
956
+ const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node.callee);
957
+ const signatures = checker.getTypeAtLocation(tsNode).getCallSignatures();
958
+ return signatures.some((sig) => isQueryResultType(sig.getReturnType()));
929
959
  }
930
960
  };
931
961
 
@@ -958,11 +988,22 @@ var rule3 = createRule3({
958
988
  const queryResultVariables = /* @__PURE__ */ new Set();
959
989
  return {
960
990
  CallExpression: (node) => {
961
- if (!ASTUtils.isIdentifierWithOneOfNames(node.callee, queryHooks) || node.parent.type !== import_utils7.AST_NODE_TYPES.VariableDeclarator || !helpers.isTanstackQueryImport(node.callee)) {
991
+ if (node.parent.type !== import_utils7.AST_NODE_TYPES.VariableDeclarator) {
962
992
  return;
963
993
  }
964
994
  const returnValue = node.parent.id;
965
- if (node.callee.name !== "useQueries" && node.callee.name !== "useSuspenseQueries") {
995
+ const isDirectHook = ASTUtils.isIdentifierWithOneOfNames(node.callee, queryHooks) && helpers.isTanstackQueryImport(node.callee);
996
+ if (!isDirectHook) {
997
+ const canReportQueryResult = returnValue.type === import_utils7.AST_NODE_TYPES.Identifier || NoRestDestructuringUtils.isObjectRestDestructuring(returnValue);
998
+ if (!canReportQueryResult || !NoRestDestructuringUtils.isQueryResultCall(
999
+ node,
1000
+ context.sourceCode.parserServices
1001
+ )) {
1002
+ return;
1003
+ }
1004
+ }
1005
+ const calleeName = ASTUtils.isIdentifier(node.callee) ? node.callee.name : null;
1006
+ if (calleeName !== "useQueries" && calleeName !== "useSuspenseQueries") {
966
1007
  if (NoRestDestructuringUtils.isObjectRestDestructuring(returnValue)) {
967
1008
  return context.report({
968
1009
  node: node.parent,
@@ -1043,7 +1084,10 @@ var rule4 = createRule4({
1043
1084
  defaultOptions: [],
1044
1085
  create: detectTanstackQueryImports((context, _options, helpers) => {
1045
1086
  const trackedVariables = {};
1087
+ const trackedCustomHooks = {};
1046
1088
  const hookAliasMap = {};
1089
+ const pendingVariableDeclarators = [];
1090
+ const pendingDependencyChecks = [];
1047
1091
  function getReactHook(node) {
1048
1092
  if (node.callee.type === "Identifier") {
1049
1093
  const calleeName = node.callee.name;
@@ -1071,6 +1115,9 @@ var rule4 = createRule4({
1071
1115
  }
1072
1116
  }
1073
1117
  }
1118
+ function isCustomHookName(hookName) {
1119
+ return /^use[A-Z0-9]/.test(hookName);
1120
+ }
1074
1121
  function hasCombineProperty(callExpression) {
1075
1122
  if (callExpression.arguments.length === 0) return false;
1076
1123
  const firstArg = callExpression.arguments[0];
@@ -1080,6 +1127,60 @@ var rule4 = createRule4({
1080
1127
  (prop) => prop.type === import_utils8.AST_NODE_TYPES.Property && prop.key.type === import_utils8.AST_NODE_TYPES.Identifier && prop.key.name === "combine"
1081
1128
  );
1082
1129
  }
1130
+ function getDirectQueryHook(callExpression) {
1131
+ if (callExpression.callee.type !== import_utils8.AST_NODE_TYPES.Identifier || !allHookNames.includes(callExpression.callee.name) || !helpers.isTanstackQueryImport(callExpression.callee)) {
1132
+ return void 0;
1133
+ }
1134
+ if ((callExpression.callee.name === "useQueries" || callExpression.callee.name === "useSuspenseQueries") && hasCombineProperty(callExpression)) {
1135
+ return void 0;
1136
+ }
1137
+ return callExpression.callee.name;
1138
+ }
1139
+ function getTrackedQueryHook(callExpression) {
1140
+ const directQueryHook = getDirectQueryHook(callExpression);
1141
+ if (directQueryHook !== void 0) {
1142
+ return directQueryHook;
1143
+ }
1144
+ if (callExpression.callee.type === import_utils8.AST_NODE_TYPES.Identifier) {
1145
+ return trackedCustomHooks[callExpression.callee.name];
1146
+ }
1147
+ return void 0;
1148
+ }
1149
+ function getReturnedQueryHook(body) {
1150
+ var _a;
1151
+ if (body.type === import_utils8.AST_NODE_TYPES.CallExpression) {
1152
+ return getDirectQueryHook(body);
1153
+ }
1154
+ if (body.type !== import_utils8.AST_NODE_TYPES.BlockStatement) {
1155
+ return void 0;
1156
+ }
1157
+ const returnStatements = body.body.filter(
1158
+ (statement) => statement.type === import_utils8.AST_NODE_TYPES.ReturnStatement
1159
+ );
1160
+ if (returnStatements.length !== 1) {
1161
+ return void 0;
1162
+ }
1163
+ const returnArgument = (_a = returnStatements[0]) == null ? void 0 : _a.argument;
1164
+ if ((returnArgument == null ? void 0 : returnArgument.type) === import_utils8.AST_NODE_TYPES.CallExpression) {
1165
+ return getDirectQueryHook(returnArgument);
1166
+ }
1167
+ return void 0;
1168
+ }
1169
+ function checkDependencyArray(reactHook, depsArray) {
1170
+ depsArray.elements.forEach((dep) => {
1171
+ if (dep !== null && dep.type === import_utils8.AST_NODE_TYPES.Identifier && trackedVariables[dep.name] !== void 0) {
1172
+ const queryHook = trackedVariables[dep.name];
1173
+ context.report({
1174
+ node: dep,
1175
+ messageId: "noUnstableDeps",
1176
+ data: {
1177
+ queryHook,
1178
+ reactHook
1179
+ }
1180
+ });
1181
+ }
1182
+ });
1183
+ }
1083
1184
  return {
1084
1185
  ImportDeclaration(node) {
1085
1186
  if (node.specifiers.length > 0 && node.importKind === "value" && node.source.value === "React") {
@@ -1090,33 +1191,50 @@ var rule4 = createRule4({
1090
1191
  });
1091
1192
  }
1092
1193
  },
1194
+ FunctionDeclaration(node) {
1195
+ if (node.id === null || !isCustomHookName(node.id.name)) {
1196
+ return;
1197
+ }
1198
+ const queryHook = getReturnedQueryHook(node.body);
1199
+ if (queryHook !== void 0) {
1200
+ trackedCustomHooks[node.id.name] = queryHook;
1201
+ }
1202
+ },
1093
1203
  VariableDeclarator(node) {
1094
- if (node.init !== null && node.init.type === import_utils8.AST_NODE_TYPES.CallExpression && node.init.callee.type === import_utils8.AST_NODE_TYPES.Identifier && allHookNames.includes(node.init.callee.name) && helpers.isTanstackQueryImport(node.init.callee)) {
1095
- if ((node.init.callee.name === "useQueries" || node.init.callee.name === "useSuspenseQueries") && hasCombineProperty(node.init)) {
1096
- return;
1204
+ if (node.id.type === import_utils8.AST_NODE_TYPES.Identifier && isCustomHookName(node.id.name) && node.init !== null && (node.init.type === import_utils8.AST_NODE_TYPES.ArrowFunctionExpression || node.init.type === import_utils8.AST_NODE_TYPES.FunctionExpression)) {
1205
+ const queryHook = getReturnedQueryHook(node.init.body);
1206
+ if (queryHook !== void 0) {
1207
+ trackedCustomHooks[node.id.name] = queryHook;
1097
1208
  }
1098
- collectVariableNames(node.id, node.init.callee.name);
1209
+ }
1210
+ if (node.init !== null && node.init.type === import_utils8.AST_NODE_TYPES.CallExpression) {
1211
+ pendingVariableDeclarators.push(node);
1099
1212
  }
1100
1213
  },
1101
1214
  CallExpression: (node) => {
1102
1215
  var _a;
1103
1216
  const reactHook = getReactHook(node);
1104
1217
  if (reactHook !== void 0 && node.arguments.length > 1 && ((_a = node.arguments[1]) == null ? void 0 : _a.type) === import_utils8.AST_NODE_TYPES.ArrayExpression) {
1105
- const depsArray = node.arguments[1].elements;
1106
- depsArray.forEach((dep) => {
1107
- if (dep !== null && dep.type === import_utils8.AST_NODE_TYPES.Identifier && trackedVariables[dep.name] !== void 0) {
1108
- const queryHook = trackedVariables[dep.name];
1109
- context.report({
1110
- node: dep,
1111
- messageId: "noUnstableDeps",
1112
- data: {
1113
- queryHook,
1114
- reactHook
1115
- }
1116
- });
1117
- }
1218
+ pendingDependencyChecks.push({
1219
+ reactHook,
1220
+ depsArray: node.arguments[1]
1118
1221
  });
1119
1222
  }
1223
+ },
1224
+ "Program:exit"() {
1225
+ pendingVariableDeclarators.forEach((node) => {
1226
+ var _a;
1227
+ if (((_a = node.init) == null ? void 0 : _a.type) !== import_utils8.AST_NODE_TYPES.CallExpression) {
1228
+ return;
1229
+ }
1230
+ const queryHook = getTrackedQueryHook(node.init);
1231
+ if (queryHook !== void 0) {
1232
+ collectVariableNames(node.id, queryHook);
1233
+ }
1234
+ });
1235
+ pendingDependencyChecks.forEach(({ reactHook, depsArray }) => {
1236
+ checkDependencyArray(reactHook, depsArray);
1237
+ });
1120
1238
  }
1121
1239
  };
1122
1240
  })