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