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