@tanstack/eslint-plugin-query 5.57.0 → 5.57.1

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.
Files changed (22) hide show
  1. package/dist/cjs/rules/infinite-query-property-order/constants.cjs +3 -5
  2. package/dist/cjs/rules/infinite-query-property-order/constants.cjs.map +1 -1
  3. package/dist/cjs/rules/infinite-query-property-order/constants.d.cts +1 -0
  4. package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.rule.cjs +1 -5
  5. package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.rule.cjs.map +1 -1
  6. package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.utils.cjs +28 -9
  7. package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.utils.cjs.map +1 -1
  8. package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.utils.d.cts +1 -1
  9. package/dist/esm/rules/infinite-query-property-order/constants.d.ts +1 -0
  10. package/dist/esm/rules/infinite-query-property-order/constants.js +4 -6
  11. package/dist/esm/rules/infinite-query-property-order/constants.js.map +1 -1
  12. package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.rule.js +2 -6
  13. package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.rule.js.map +1 -1
  14. package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.utils.d.ts +1 -1
  15. package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.utils.js +28 -9
  16. package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.utils.js.map +1 -1
  17. package/package.json +1 -1
  18. package/src/__tests__/infinite-query-property-order.rule.test.ts +48 -6
  19. package/src/__tests__/infinite-query-property-order.utils.test.ts +28 -7
  20. package/src/rules/infinite-query-property-order/constants.ts +4 -0
  21. package/src/rules/infinite-query-property-order/infinite-query-property-order.rule.ts +4 -6
  22. package/src/rules/infinite-query-property-order/infinite-query-property-order.utils.ts +43 -14
@@ -5,11 +5,9 @@ const infiniteQueryFunctions = [
5
5
  "useInfiniteQuery",
6
6
  "useSuspenseInfiniteQuery"
7
7
  ];
8
- const checkedProperties = [
9
- "queryFn",
10
- "getPreviousPageParam",
11
- "getNextPageParam"
8
+ const sortRules = [
9
+ [["queryFn"], ["getPreviousPageParam", "getNextPageParam"]]
12
10
  ];
13
- exports.checkedProperties = checkedProperties;
14
11
  exports.infiniteQueryFunctions = infiniteQueryFunctions;
12
+ exports.sortRules = sortRules;
15
13
  //# sourceMappingURL=constants.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.cjs","sources":["../../../../src/rules/infinite-query-property-order/constants.ts"],"sourcesContent":["export const infiniteQueryFunctions = [\n 'infiniteQueryOptions',\n 'useInfiniteQuery',\n 'useSuspenseInfiniteQuery',\n] as const\n\nexport type InfiniteQueryFunctions = (typeof infiniteQueryFunctions)[number]\n\nexport const checkedProperties = [\n 'queryFn',\n 'getPreviousPageParam',\n 'getNextPageParam',\n] as const\n"],"names":[],"mappings":";;AAAO,MAAM,yBAAyB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AACF;AAIO,MAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACF;;;"}
1
+ {"version":3,"file":"constants.cjs","sources":["../../../../src/rules/infinite-query-property-order/constants.ts"],"sourcesContent":["export const infiniteQueryFunctions = [\n 'infiniteQueryOptions',\n 'useInfiniteQuery',\n 'useSuspenseInfiniteQuery',\n] as const\n\nexport type InfiniteQueryFunctions = (typeof infiniteQueryFunctions)[number]\n\nexport const checkedProperties = [\n 'queryFn',\n 'getPreviousPageParam',\n 'getNextPageParam',\n] as const\n\nexport const sortRules = [\n [['queryFn'], ['getPreviousPageParam', 'getNextPageParam']],\n] as const\n"],"names":[],"mappings":";;AAAO,MAAM,yBAAyB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AACF;AAUO,MAAM,YAAY;AAAA,EACvB,CAAC,CAAC,SAAS,GAAG,CAAC,wBAAwB,kBAAkB,CAAC;AAC5D;;;"}
@@ -1,3 +1,4 @@
1
1
  export declare const infiniteQueryFunctions: readonly ["infiniteQueryOptions", "useInfiniteQuery", "useSuspenseInfiniteQuery"];
2
2
  export type InfiniteQueryFunctions = (typeof infiniteQueryFunctions)[number];
3
3
  export declare const checkedProperties: readonly ["queryFn", "getPreviousPageParam", "getNextPageParam"];
4
+ export declare const sortRules: readonly [readonly [readonly ["queryFn"], readonly ["getPreviousPageParam", "getNextPageParam"]]];
@@ -57,11 +57,7 @@ const rule = createRule({
57
57
  }
58
58
  return [];
59
59
  });
60
- const sortedProperties = infiniteQueryPropertyOrder_utils.sortDataByOrder(
61
- properties,
62
- constants.checkedProperties,
63
- "name"
64
- );
60
+ const sortedProperties = infiniteQueryPropertyOrder_utils.sortDataByOrder(properties, constants.sortRules, "name");
65
61
  if (sortedProperties === null) {
66
62
  return;
67
63
  }
@@ -1 +1 @@
1
- {"version":3,"file":"infinite-query-property-order.rule.cjs","sources":["../../../../src/rules/infinite-query-property-order/infinite-query-property-order.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'\nimport { sortDataByOrder } from './infinite-query-property-order.utils'\nimport { checkedProperties, infiniteQueryFunctions } from './constants'\nimport type { InfiniteQueryFunctions } from './constants'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst infiniteQueryFunctionsSet = new Set(infiniteQueryFunctions)\nfunction isInfiniteQueryFunction(node: any): node is InfiniteQueryFunctions {\n return infiniteQueryFunctionsSet.has(node)\n}\n\nexport const name = 'infinite-query-property-order'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Ensure correct order of inference sensitive properties for infinite queries',\n recommended: 'error',\n },\n messages: {\n invalidOrder: 'Invalid order of properties for `{{function}}`.',\n },\n schema: [],\n hasSuggestions: true,\n fixable: 'code',\n },\n defaultOptions: [],\n\n create: detectTanstackQueryImports((context) => {\n return {\n CallExpression(node) {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) {\n return\n }\n const infiniteQueryFunction = node.callee.name\n if (!isInfiniteQueryFunction(infiniteQueryFunction)) {\n return\n }\n const argument = node.arguments[0]\n if (argument === undefined || argument.type !== 'ObjectExpression') {\n return\n }\n\n const allProperties = argument.properties\n if (allProperties.length < 2) {\n return\n }\n\n const properties = allProperties.flatMap((p) => {\n if (\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier\n ) {\n return { name: p.key.name, property: p }\n } else if (p.type === AST_NODE_TYPES.SpreadElement) {\n if (p.argument.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.name, property: p }\n } else {\n throw new Error('Unsupported spread element')\n }\n }\n return []\n })\n\n const sortedProperties = sortDataByOrder(\n properties,\n checkedProperties,\n 'name',\n )\n if (sortedProperties === null) {\n return\n }\n context.report({\n node: argument,\n data: { function: node.callee.name },\n messageId: 'invalidOrder',\n fix(fixer) {\n const sourceCode = context.sourceCode\n\n const text = sortedProperties.reduce(\n (sourceText, specifier, index) => {\n let text = ''\n if (index < allProperties.length - 1) {\n text = sourceCode\n .getText()\n .slice(\n allProperties[index]!.range[1],\n allProperties[index + 1]!.range[0],\n )\n }\n return (\n sourceText + sourceCode.getText(specifier.property) + text\n )\n },\n '',\n )\n return fixer.replaceTextRange(\n [allProperties[0]!.range[0], allProperties.at(-1)!.range[1]],\n text,\n )\n },\n })\n },\n }\n }),\n})\n"],"names":["ESLintUtils","getDocsUrl","infiniteQueryFunctions","detectTanstackQueryImports","AST_NODE_TYPES","sortDataByOrder","checkedProperties","text"],"mappings":";;;;;;;AASA,MAAM,aAAaA,MAAY,YAAA,YAA2BC,WAAAA,UAAU;AAEpE,MAAM,4BAA4B,IAAI,IAAIC,UAAAA,sBAAsB;AAChE,SAAS,wBAAwB,MAA2C;AACnE,SAAA,0BAA0B,IAAI,IAAI;AAC3C;AAEO,MAAM,OAAO;AAEb,MAAM,OAAO,WAAW;AAAA,EAC7B;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,MACF,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,cAAc;AAAA,IAChB;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,gBAAgB;AAAA,IAChB,SAAS;AAAA,EACX;AAAA,EACA,gBAAgB,CAAC;AAAA,EAEjB,QAAQC,wBAAAA,2BAA2B,CAAC,YAAY;AACvC,WAAA;AAAA,MACL,eAAe,MAAM;AACnB,YAAI,KAAK,OAAO,SAASC,MAAAA,eAAe,YAAY;AAClD;AAAA,QACF;AACM,cAAA,wBAAwB,KAAK,OAAO;AACtC,YAAA,CAAC,wBAAwB,qBAAqB,GAAG;AACnD;AAAA,QACF;AACM,cAAA,WAAW,KAAK,UAAU,CAAC;AACjC,YAAI,aAAa,UAAa,SAAS,SAAS,oBAAoB;AAClE;AAAA,QACF;AAEA,cAAM,gBAAgB,SAAS;AAC3B,YAAA,cAAc,SAAS,GAAG;AAC5B;AAAA,QACF;AAEA,cAAM,aAAa,cAAc,QAAQ,CAAC,MAAM;AAE5C,cAAA,EAAE,SAASA,MAAAA,eAAe,YAC1B,EAAE,IAAI,SAASA,qBAAe,YAC9B;AACA,mBAAO,EAAE,MAAM,EAAE,IAAI,MAAM,UAAU;UAC5B,WAAA,EAAE,SAASA,MAAAA,eAAe,eAAe;AAClD,gBAAI,EAAE,SAAS,SAASA,MAAAA,eAAe,YAAY;AACjD,qBAAO,EAAE,MAAM,EAAE,SAAS,MAAM,UAAU;YAAE,OACvC;AACC,oBAAA,IAAI,MAAM,4BAA4B;AAAA,YAC9C;AAAA,UACF;AACA,iBAAO;QAAC,CACT;AAED,cAAM,mBAAmBC,iCAAA;AAAA,UACvB;AAAA,UACAC,UAAA;AAAA,UACA;AAAA,QAAA;AAEF,YAAI,qBAAqB,MAAM;AAC7B;AAAA,QACF;AACA,gBAAQ,OAAO;AAAA,UACb,MAAM;AAAA,UACN,MAAM,EAAE,UAAU,KAAK,OAAO,KAAK;AAAA,UACnC,WAAW;AAAA,UACX,IAAI,OAAO;AACT,kBAAM,aAAa,QAAQ;AAE3B,kBAAM,OAAO,iBAAiB;AAAA,cAC5B,CAAC,YAAY,WAAW,UAAU;AAChC,oBAAIC,QAAO;AACP,oBAAA,QAAQ,cAAc,SAAS,GAAG;AACpCA,0BAAO,WACJ,QAAA,EACA;AAAA,oBACC,cAAc,KAAK,EAAG,MAAM,CAAC;AAAA,oBAC7B,cAAc,QAAQ,CAAC,EAAG,MAAM,CAAC;AAAA,kBAAA;AAAA,gBAEvC;AACA,uBACE,aAAa,WAAW,QAAQ,UAAU,QAAQ,IAAIA;AAAAA,cAE1D;AAAA,cACA;AAAA,YAAA;AAEF,mBAAO,MAAM;AAAA,cACX,CAAC,cAAc,CAAC,EAAG,MAAM,CAAC,GAAG,cAAc,GAAG,EAAE,EAAG,MAAM,CAAC,CAAC;AAAA,cAC3D;AAAA,YAAA;AAAA,UAEJ;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IAAA;AAAA,EACF,CACD;AACH,CAAC;;;"}
1
+ {"version":3,"file":"infinite-query-property-order.rule.cjs","sources":["../../../../src/rules/infinite-query-property-order/infinite-query-property-order.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'\nimport { sortDataByOrder } from './infinite-query-property-order.utils'\nimport { infiniteQueryFunctions, sortRules } from './constants'\nimport type { InfiniteQueryFunctions } from './constants'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst infiniteQueryFunctionsSet = new Set(infiniteQueryFunctions)\nfunction isInfiniteQueryFunction(node: any): node is InfiniteQueryFunctions {\n return infiniteQueryFunctionsSet.has(node)\n}\n\nexport const name = 'infinite-query-property-order'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Ensure correct order of inference sensitive properties for infinite queries',\n recommended: 'error',\n },\n messages: {\n invalidOrder: 'Invalid order of properties for `{{function}}`.',\n },\n schema: [],\n hasSuggestions: true,\n fixable: 'code',\n },\n defaultOptions: [],\n\n create: detectTanstackQueryImports((context) => {\n return {\n CallExpression(node) {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) {\n return\n }\n const infiniteQueryFunction = node.callee.name\n if (!isInfiniteQueryFunction(infiniteQueryFunction)) {\n return\n }\n const argument = node.arguments[0]\n if (argument === undefined || argument.type !== 'ObjectExpression') {\n return\n }\n\n const allProperties = argument.properties\n\n // no need to sort if there is at max 1 property\n if (allProperties.length < 2) {\n return\n }\n\n const properties = allProperties.flatMap((p) => {\n if (\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier\n ) {\n return { name: p.key.name, property: p }\n } else if (p.type === AST_NODE_TYPES.SpreadElement) {\n if (p.argument.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.name, property: p }\n } else {\n throw new Error('Unsupported spread element')\n }\n }\n return []\n })\n\n const sortedProperties = sortDataByOrder(properties, sortRules, 'name')\n if (sortedProperties === null) {\n return\n }\n context.report({\n node: argument,\n data: { function: node.callee.name },\n messageId: 'invalidOrder',\n fix(fixer) {\n const sourceCode = context.sourceCode\n\n const text = sortedProperties.reduce(\n (sourceText, specifier, index) => {\n let text = ''\n if (index < allProperties.length - 1) {\n text = sourceCode\n .getText()\n .slice(\n allProperties[index]!.range[1],\n allProperties[index + 1]!.range[0],\n )\n }\n return (\n sourceText + sourceCode.getText(specifier.property) + text\n )\n },\n '',\n )\n return fixer.replaceTextRange(\n [allProperties[0]!.range[0], allProperties.at(-1)!.range[1]],\n text,\n )\n },\n })\n },\n }\n }),\n})\n"],"names":["ESLintUtils","getDocsUrl","infiniteQueryFunctions","detectTanstackQueryImports","AST_NODE_TYPES","sortDataByOrder","sortRules","text"],"mappings":";;;;;;;AASA,MAAM,aAAaA,MAAY,YAAA,YAA2BC,WAAAA,UAAU;AAEpE,MAAM,4BAA4B,IAAI,IAAIC,UAAAA,sBAAsB;AAChE,SAAS,wBAAwB,MAA2C;AACnE,SAAA,0BAA0B,IAAI,IAAI;AAC3C;AAEO,MAAM,OAAO;AAEb,MAAM,OAAO,WAAW;AAAA,EAC7B;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,MACF,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,cAAc;AAAA,IAChB;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,gBAAgB;AAAA,IAChB,SAAS;AAAA,EACX;AAAA,EACA,gBAAgB,CAAC;AAAA,EAEjB,QAAQC,wBAAAA,2BAA2B,CAAC,YAAY;AACvC,WAAA;AAAA,MACL,eAAe,MAAM;AACnB,YAAI,KAAK,OAAO,SAASC,MAAAA,eAAe,YAAY;AAClD;AAAA,QACF;AACM,cAAA,wBAAwB,KAAK,OAAO;AACtC,YAAA,CAAC,wBAAwB,qBAAqB,GAAG;AACnD;AAAA,QACF;AACM,cAAA,WAAW,KAAK,UAAU,CAAC;AACjC,YAAI,aAAa,UAAa,SAAS,SAAS,oBAAoB;AAClE;AAAA,QACF;AAEA,cAAM,gBAAgB,SAAS;AAG3B,YAAA,cAAc,SAAS,GAAG;AAC5B;AAAA,QACF;AAEA,cAAM,aAAa,cAAc,QAAQ,CAAC,MAAM;AAE5C,cAAA,EAAE,SAASA,MAAAA,eAAe,YAC1B,EAAE,IAAI,SAASA,qBAAe,YAC9B;AACA,mBAAO,EAAE,MAAM,EAAE,IAAI,MAAM,UAAU;UAC5B,WAAA,EAAE,SAASA,MAAAA,eAAe,eAAe;AAClD,gBAAI,EAAE,SAAS,SAASA,MAAAA,eAAe,YAAY;AACjD,qBAAO,EAAE,MAAM,EAAE,SAAS,MAAM,UAAU;YAAE,OACvC;AACC,oBAAA,IAAI,MAAM,4BAA4B;AAAA,YAC9C;AAAA,UACF;AACA,iBAAO;QAAC,CACT;AAED,cAAM,mBAAmBC,iCAAA,gBAAgB,YAAYC,UAAA,WAAW,MAAM;AACtE,YAAI,qBAAqB,MAAM;AAC7B;AAAA,QACF;AACA,gBAAQ,OAAO;AAAA,UACb,MAAM;AAAA,UACN,MAAM,EAAE,UAAU,KAAK,OAAO,KAAK;AAAA,UACnC,WAAW;AAAA,UACX,IAAI,OAAO;AACT,kBAAM,aAAa,QAAQ;AAE3B,kBAAM,OAAO,iBAAiB;AAAA,cAC5B,CAAC,YAAY,WAAW,UAAU;AAChC,oBAAIC,QAAO;AACP,oBAAA,QAAQ,cAAc,SAAS,GAAG;AACpCA,0BAAO,WACJ,QAAA,EACA;AAAA,oBACC,cAAc,KAAK,EAAG,MAAM,CAAC;AAAA,oBAC7B,cAAc,QAAQ,CAAC,EAAG,MAAM,CAAC;AAAA,kBAAA;AAAA,gBAEvC;AACA,uBACE,aAAa,WAAW,QAAQ,UAAU,QAAQ,IAAIA;AAAAA,cAE1D;AAAA,cACA;AAAA,YAAA;AAEF,mBAAO,MAAM;AAAA,cACX,CAAC,cAAc,CAAC,EAAG,MAAM,CAAC,GAAG,cAAc,GAAG,EAAE,EAAG,MAAM,CAAC,CAAC;AAAA,cAC3D;AAAA,YAAA;AAAA,UAEJ;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IAAA;AAAA,EACF,CACD;AACH,CAAC;;;"}
@@ -1,16 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- function sortDataByOrder(data, orderArray, key) {
4
- const orderMap = new Map(orderArray.map((item, index) => [item, index]));
5
- const inOrderArray = data.filter((item) => orderMap.has(item[key])).sort((a, b) => {
6
- const indexA = orderMap.get(a[key]);
7
- const indexB = orderMap.get(b[key]);
8
- return indexA - indexB;
9
- });
10
- const inOrderIterator = inOrderArray.values();
3
+ function sortDataByOrder(data, orderRules, key) {
4
+ const getSubsetIndex = (item, subsets) => {
5
+ var _a;
6
+ for (let i = 0; i < subsets.length; i++) {
7
+ if ((_a = subsets[i]) == null ? void 0 : _a.includes(item)) {
8
+ return i;
9
+ }
10
+ }
11
+ return null;
12
+ };
13
+ const orderSets = orderRules.reduce(
14
+ (sets, [A, B]) => [...sets, A, B],
15
+ []
16
+ );
17
+ const inOrderArray = data.filter(
18
+ (item) => getSubsetIndex(item[key], orderSets) !== null
19
+ );
11
20
  let wasResorted = false;
21
+ const sortedArray = inOrderArray.sort((a, b) => {
22
+ const aKey = a[key], bKey = b[key];
23
+ const aSubsetIndex = getSubsetIndex(aKey, orderSets);
24
+ const bSubsetIndex = getSubsetIndex(bKey, orderSets);
25
+ if (aSubsetIndex !== null && bSubsetIndex !== null && aSubsetIndex !== bSubsetIndex) {
26
+ return aSubsetIndex - bSubsetIndex;
27
+ }
28
+ return 0;
29
+ });
30
+ const inOrderIterator = sortedArray.values();
12
31
  const result = data.map((item) => {
13
- if (orderMap.has(item[key])) {
32
+ if (getSubsetIndex(item[key], orderSets) !== null) {
14
33
  const sortedItem = inOrderIterator.next().value;
15
34
  if (sortedItem[key] !== item[key]) {
16
35
  wasResorted = true;
@@ -1 +1 @@
1
- {"version":3,"file":"infinite-query-property-order.utils.cjs","sources":["../../../../src/rules/infinite-query-property-order/infinite-query-property-order.utils.ts"],"sourcesContent":["export function sortDataByOrder<T, TKey extends keyof T>(\n data: Array<T> | ReadonlyArray<T>,\n orderArray: Array<T[TKey]> | ReadonlyArray<T[TKey]>,\n key: TKey,\n): Array<T> | null {\n const orderMap = new Map(orderArray.map((item, index) => [item, index]))\n\n // Separate items that are in orderArray from those that are not\n const inOrderArray = data\n .filter((item) => orderMap.has(item[key]))\n .sort((a, b) => {\n const indexA = orderMap.get(a[key])!\n const indexB = orderMap.get(b[key])!\n\n return indexA - indexB\n })\n\n const inOrderIterator = inOrderArray.values()\n\n // `as boolean` is needed to avoid TS incorrectly inferring that wasResorted is always `true`\n let wasResorted = false as boolean\n\n const result = data.map((item) => {\n if (orderMap.has(item[key])) {\n const sortedItem = inOrderIterator.next().value!\n if (sortedItem[key] !== item[key]) {\n wasResorted = true\n }\n return sortedItem\n }\n return item\n })\n\n if (!wasResorted) {\n return null\n }\n return result\n}\n"],"names":[],"mappings":";;AAAgB,SAAA,gBACd,MACA,YACA,KACiB;AACjB,QAAM,WAAW,IAAI,IAAI,WAAW,IAAI,CAAC,MAAM,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC;AAGvE,QAAM,eAAe,KAClB,OAAO,CAAC,SAAS,SAAS,IAAI,KAAK,GAAG,CAAC,CAAC,EACxC,KAAK,CAAC,GAAG,MAAM;AACd,UAAM,SAAS,SAAS,IAAI,EAAE,GAAG,CAAC;AAClC,UAAM,SAAS,SAAS,IAAI,EAAE,GAAG,CAAC;AAElC,WAAO,SAAS;AAAA,EAAA,CACjB;AAEG,QAAA,kBAAkB,aAAa;AAGrC,MAAI,cAAc;AAElB,QAAM,SAAS,KAAK,IAAI,CAAC,SAAS;AAChC,QAAI,SAAS,IAAI,KAAK,GAAG,CAAC,GAAG;AACrB,YAAA,aAAa,gBAAgB,KAAA,EAAO;AAC1C,UAAI,WAAW,GAAG,MAAM,KAAK,GAAG,GAAG;AACnB,sBAAA;AAAA,MAChB;AACO,aAAA;AAAA,IACT;AACO,WAAA;AAAA,EAAA,CACR;AAED,MAAI,CAAC,aAAa;AACT,WAAA;AAAA,EACT;AACO,SAAA;AACT;;"}
1
+ {"version":3,"file":"infinite-query-property-order.utils.cjs","sources":["../../../../src/rules/infinite-query-property-order/infinite-query-property-order.utils.ts"],"sourcesContent":["export function sortDataByOrder<T, TKey extends keyof T>(\n data: Array<T> | ReadonlyArray<T>,\n orderRules: ReadonlyArray<\n Readonly<[ReadonlyArray<T[TKey]>, ReadonlyArray<T[TKey]>]>\n >,\n key: TKey,\n): Array<T> | null {\n const getSubsetIndex = (\n item: T[TKey],\n subsets: ReadonlyArray<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,\n ): number | null => {\n for (let i = 0; i < subsets.length; i++) {\n if (subsets[i]?.includes(item)) {\n return i\n }\n }\n return null\n }\n\n const orderSets = orderRules.reduce(\n (sets, [A, B]) => [...sets, A, B],\n [] as Array<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,\n )\n\n const inOrderArray = data.filter(\n (item) => getSubsetIndex(item[key], orderSets) !== null,\n )\n\n let wasResorted = false as boolean\n\n // Sort by the relative order defined by the rules\n const sortedArray = inOrderArray.sort((a, b) => {\n const aKey = a[key],\n bKey = b[key]\n const aSubsetIndex = getSubsetIndex(aKey, orderSets)\n const bSubsetIndex = getSubsetIndex(bKey, orderSets)\n\n // If both items belong to different subsets, sort by their subset order\n if (\n aSubsetIndex !== null &&\n bSubsetIndex !== null &&\n aSubsetIndex !== bSubsetIndex\n ) {\n return aSubsetIndex - bSubsetIndex\n }\n\n // If both items belong to the same subset or neither is in the subset, keep their relative order\n return 0\n })\n\n const inOrderIterator = sortedArray.values()\n const result = data.map((item) => {\n if (getSubsetIndex(item[key], orderSets) !== null) {\n const sortedItem = inOrderIterator.next().value!\n if (sortedItem[key] !== item[key]) {\n wasResorted = true\n }\n return sortedItem\n }\n return item\n })\n\n if (!wasResorted) {\n return null\n }\n return result\n}\n"],"names":[],"mappings":";;AAAgB,SAAA,gBACd,MACA,YAGA,KACiB;AACX,QAAA,iBAAiB,CACrB,MACA,YACkB;;AAClB,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,WAAI,aAAQ,CAAC,MAAT,mBAAY,SAAS,OAAO;AACvB,eAAA;AAAA,MACT;AAAA,IACF;AACO,WAAA;AAAA,EAAA;AAGT,QAAM,YAAY,WAAW;AAAA,IAC3B,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC;AAAA,IAChC,CAAC;AAAA,EAAA;AAGH,QAAM,eAAe,KAAK;AAAA,IACxB,CAAC,SAAS,eAAe,KAAK,GAAG,GAAG,SAAS,MAAM;AAAA,EAAA;AAGrD,MAAI,cAAc;AAGlB,QAAM,cAAc,aAAa,KAAK,CAAC,GAAG,MAAM;AAC9C,UAAM,OAAO,EAAE,GAAG,GAChB,OAAO,EAAE,GAAG;AACR,UAAA,eAAe,eAAe,MAAM,SAAS;AAC7C,UAAA,eAAe,eAAe,MAAM,SAAS;AAGnD,QACE,iBAAiB,QACjB,iBAAiB,QACjB,iBAAiB,cACjB;AACA,aAAO,eAAe;AAAA,IACxB;AAGO,WAAA;AAAA,EAAA,CACR;AAEK,QAAA,kBAAkB,YAAY;AACpC,QAAM,SAAS,KAAK,IAAI,CAAC,SAAS;AAChC,QAAI,eAAe,KAAK,GAAG,GAAG,SAAS,MAAM,MAAM;AAC3C,YAAA,aAAa,gBAAgB,KAAA,EAAO;AAC1C,UAAI,WAAW,GAAG,MAAM,KAAK,GAAG,GAAG;AACnB,sBAAA;AAAA,MAChB;AACO,aAAA;AAAA,IACT;AACO,WAAA;AAAA,EAAA,CACR;AAED,MAAI,CAAC,aAAa;AACT,WAAA;AAAA,EACT;AACO,SAAA;AACT;;"}
@@ -1 +1 @@
1
- export declare function sortDataByOrder<T, TKey extends keyof T>(data: Array<T> | ReadonlyArray<T>, orderArray: Array<T[TKey]> | ReadonlyArray<T[TKey]>, key: TKey): Array<T> | null;
1
+ export declare function sortDataByOrder<T, TKey extends keyof T>(data: Array<T> | ReadonlyArray<T>, orderRules: ReadonlyArray<Readonly<[ReadonlyArray<T[TKey]>, ReadonlyArray<T[TKey]>]>>, key: TKey): Array<T> | null;
@@ -1,3 +1,4 @@
1
1
  export declare const infiniteQueryFunctions: readonly ["infiniteQueryOptions", "useInfiniteQuery", "useSuspenseInfiniteQuery"];
2
2
  export type InfiniteQueryFunctions = (typeof infiniteQueryFunctions)[number];
3
3
  export declare const checkedProperties: readonly ["queryFn", "getPreviousPageParam", "getNextPageParam"];
4
+ export declare const sortRules: readonly [readonly [readonly ["queryFn"], readonly ["getPreviousPageParam", "getNextPageParam"]]];
@@ -3,13 +3,11 @@ const infiniteQueryFunctions = [
3
3
  "useInfiniteQuery",
4
4
  "useSuspenseInfiniteQuery"
5
5
  ];
6
- const checkedProperties = [
7
- "queryFn",
8
- "getPreviousPageParam",
9
- "getNextPageParam"
6
+ const sortRules = [
7
+ [["queryFn"], ["getPreviousPageParam", "getNextPageParam"]]
10
8
  ];
11
9
  export {
12
- checkedProperties,
13
- infiniteQueryFunctions
10
+ infiniteQueryFunctions,
11
+ sortRules
14
12
  };
15
13
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sources":["../../../../src/rules/infinite-query-property-order/constants.ts"],"sourcesContent":["export const infiniteQueryFunctions = [\n 'infiniteQueryOptions',\n 'useInfiniteQuery',\n 'useSuspenseInfiniteQuery',\n] as const\n\nexport type InfiniteQueryFunctions = (typeof infiniteQueryFunctions)[number]\n\nexport const checkedProperties = [\n 'queryFn',\n 'getPreviousPageParam',\n 'getNextPageParam',\n] as const\n"],"names":[],"mappings":"AAAO,MAAM,yBAAyB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AACF;AAIO,MAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACF;"}
1
+ {"version":3,"file":"constants.js","sources":["../../../../src/rules/infinite-query-property-order/constants.ts"],"sourcesContent":["export const infiniteQueryFunctions = [\n 'infiniteQueryOptions',\n 'useInfiniteQuery',\n 'useSuspenseInfiniteQuery',\n] as const\n\nexport type InfiniteQueryFunctions = (typeof infiniteQueryFunctions)[number]\n\nexport const checkedProperties = [\n 'queryFn',\n 'getPreviousPageParam',\n 'getNextPageParam',\n] as const\n\nexport const sortRules = [\n [['queryFn'], ['getPreviousPageParam', 'getNextPageParam']],\n] as const\n"],"names":[],"mappings":"AAAO,MAAM,yBAAyB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AACF;AAUO,MAAM,YAAY;AAAA,EACvB,CAAC,CAAC,SAAS,GAAG,CAAC,wBAAwB,kBAAkB,CAAC;AAC5D;"}
@@ -2,7 +2,7 @@ import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
2
2
  import { getDocsUrl } from "../../utils/get-docs-url.js";
3
3
  import { detectTanstackQueryImports } from "../../utils/detect-react-query-imports.js";
4
4
  import { sortDataByOrder } from "./infinite-query-property-order.utils.js";
5
- import { infiniteQueryFunctions, checkedProperties } from "./constants.js";
5
+ import { infiniteQueryFunctions, sortRules } from "./constants.js";
6
6
  const createRule = ESLintUtils.RuleCreator(getDocsUrl);
7
7
  const infiniteQueryFunctionsSet = new Set(infiniteQueryFunctions);
8
8
  function isInfiniteQueryFunction(node) {
@@ -55,11 +55,7 @@ const rule = createRule({
55
55
  }
56
56
  return [];
57
57
  });
58
- const sortedProperties = sortDataByOrder(
59
- properties,
60
- checkedProperties,
61
- "name"
62
- );
58
+ const sortedProperties = sortDataByOrder(properties, sortRules, "name");
63
59
  if (sortedProperties === null) {
64
60
  return;
65
61
  }
@@ -1 +1 @@
1
- {"version":3,"file":"infinite-query-property-order.rule.js","sources":["../../../../src/rules/infinite-query-property-order/infinite-query-property-order.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'\nimport { sortDataByOrder } from './infinite-query-property-order.utils'\nimport { checkedProperties, infiniteQueryFunctions } from './constants'\nimport type { InfiniteQueryFunctions } from './constants'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst infiniteQueryFunctionsSet = new Set(infiniteQueryFunctions)\nfunction isInfiniteQueryFunction(node: any): node is InfiniteQueryFunctions {\n return infiniteQueryFunctionsSet.has(node)\n}\n\nexport const name = 'infinite-query-property-order'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Ensure correct order of inference sensitive properties for infinite queries',\n recommended: 'error',\n },\n messages: {\n invalidOrder: 'Invalid order of properties for `{{function}}`.',\n },\n schema: [],\n hasSuggestions: true,\n fixable: 'code',\n },\n defaultOptions: [],\n\n create: detectTanstackQueryImports((context) => {\n return {\n CallExpression(node) {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) {\n return\n }\n const infiniteQueryFunction = node.callee.name\n if (!isInfiniteQueryFunction(infiniteQueryFunction)) {\n return\n }\n const argument = node.arguments[0]\n if (argument === undefined || argument.type !== 'ObjectExpression') {\n return\n }\n\n const allProperties = argument.properties\n if (allProperties.length < 2) {\n return\n }\n\n const properties = allProperties.flatMap((p) => {\n if (\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier\n ) {\n return { name: p.key.name, property: p }\n } else if (p.type === AST_NODE_TYPES.SpreadElement) {\n if (p.argument.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.name, property: p }\n } else {\n throw new Error('Unsupported spread element')\n }\n }\n return []\n })\n\n const sortedProperties = sortDataByOrder(\n properties,\n checkedProperties,\n 'name',\n )\n if (sortedProperties === null) {\n return\n }\n context.report({\n node: argument,\n data: { function: node.callee.name },\n messageId: 'invalidOrder',\n fix(fixer) {\n const sourceCode = context.sourceCode\n\n const text = sortedProperties.reduce(\n (sourceText, specifier, index) => {\n let text = ''\n if (index < allProperties.length - 1) {\n text = sourceCode\n .getText()\n .slice(\n allProperties[index]!.range[1],\n allProperties[index + 1]!.range[0],\n )\n }\n return (\n sourceText + sourceCode.getText(specifier.property) + text\n )\n },\n '',\n )\n return fixer.replaceTextRange(\n [allProperties[0]!.range[0], allProperties.at(-1)!.range[1]],\n text,\n )\n },\n })\n },\n }\n }),\n})\n"],"names":["text"],"mappings":";;;;;AASA,MAAM,aAAa,YAAY,YAA2B,UAAU;AAEpE,MAAM,4BAA4B,IAAI,IAAI,sBAAsB;AAChE,SAAS,wBAAwB,MAA2C;AACnE,SAAA,0BAA0B,IAAI,IAAI;AAC3C;AAEO,MAAM,OAAO;AAEb,MAAM,OAAO,WAAW;AAAA,EAC7B;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,MACF,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,cAAc;AAAA,IAChB;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,gBAAgB;AAAA,IAChB,SAAS;AAAA,EACX;AAAA,EACA,gBAAgB,CAAC;AAAA,EAEjB,QAAQ,2BAA2B,CAAC,YAAY;AACvC,WAAA;AAAA,MACL,eAAe,MAAM;AACnB,YAAI,KAAK,OAAO,SAAS,eAAe,YAAY;AAClD;AAAA,QACF;AACM,cAAA,wBAAwB,KAAK,OAAO;AACtC,YAAA,CAAC,wBAAwB,qBAAqB,GAAG;AACnD;AAAA,QACF;AACM,cAAA,WAAW,KAAK,UAAU,CAAC;AACjC,YAAI,aAAa,UAAa,SAAS,SAAS,oBAAoB;AAClE;AAAA,QACF;AAEA,cAAM,gBAAgB,SAAS;AAC3B,YAAA,cAAc,SAAS,GAAG;AAC5B;AAAA,QACF;AAEA,cAAM,aAAa,cAAc,QAAQ,CAAC,MAAM;AAE5C,cAAA,EAAE,SAAS,eAAe,YAC1B,EAAE,IAAI,SAAS,eAAe,YAC9B;AACA,mBAAO,EAAE,MAAM,EAAE,IAAI,MAAM,UAAU;UAC5B,WAAA,EAAE,SAAS,eAAe,eAAe;AAClD,gBAAI,EAAE,SAAS,SAAS,eAAe,YAAY;AACjD,qBAAO,EAAE,MAAM,EAAE,SAAS,MAAM,UAAU;YAAE,OACvC;AACC,oBAAA,IAAI,MAAM,4BAA4B;AAAA,YAC9C;AAAA,UACF;AACA,iBAAO;QAAC,CACT;AAED,cAAM,mBAAmB;AAAA,UACvB;AAAA,UACA;AAAA,UACA;AAAA,QAAA;AAEF,YAAI,qBAAqB,MAAM;AAC7B;AAAA,QACF;AACA,gBAAQ,OAAO;AAAA,UACb,MAAM;AAAA,UACN,MAAM,EAAE,UAAU,KAAK,OAAO,KAAK;AAAA,UACnC,WAAW;AAAA,UACX,IAAI,OAAO;AACT,kBAAM,aAAa,QAAQ;AAE3B,kBAAM,OAAO,iBAAiB;AAAA,cAC5B,CAAC,YAAY,WAAW,UAAU;AAChC,oBAAIA,QAAO;AACP,oBAAA,QAAQ,cAAc,SAAS,GAAG;AACpCA,0BAAO,WACJ,QAAA,EACA;AAAA,oBACC,cAAc,KAAK,EAAG,MAAM,CAAC;AAAA,oBAC7B,cAAc,QAAQ,CAAC,EAAG,MAAM,CAAC;AAAA,kBAAA;AAAA,gBAEvC;AACA,uBACE,aAAa,WAAW,QAAQ,UAAU,QAAQ,IAAIA;AAAAA,cAE1D;AAAA,cACA;AAAA,YAAA;AAEF,mBAAO,MAAM;AAAA,cACX,CAAC,cAAc,CAAC,EAAG,MAAM,CAAC,GAAG,cAAc,GAAG,EAAE,EAAG,MAAM,CAAC,CAAC;AAAA,cAC3D;AAAA,YAAA;AAAA,UAEJ;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IAAA;AAAA,EACF,CACD;AACH,CAAC;"}
1
+ {"version":3,"file":"infinite-query-property-order.rule.js","sources":["../../../../src/rules/infinite-query-property-order/infinite-query-property-order.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'\nimport { sortDataByOrder } from './infinite-query-property-order.utils'\nimport { infiniteQueryFunctions, sortRules } from './constants'\nimport type { InfiniteQueryFunctions } from './constants'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst infiniteQueryFunctionsSet = new Set(infiniteQueryFunctions)\nfunction isInfiniteQueryFunction(node: any): node is InfiniteQueryFunctions {\n return infiniteQueryFunctionsSet.has(node)\n}\n\nexport const name = 'infinite-query-property-order'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Ensure correct order of inference sensitive properties for infinite queries',\n recommended: 'error',\n },\n messages: {\n invalidOrder: 'Invalid order of properties for `{{function}}`.',\n },\n schema: [],\n hasSuggestions: true,\n fixable: 'code',\n },\n defaultOptions: [],\n\n create: detectTanstackQueryImports((context) => {\n return {\n CallExpression(node) {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) {\n return\n }\n const infiniteQueryFunction = node.callee.name\n if (!isInfiniteQueryFunction(infiniteQueryFunction)) {\n return\n }\n const argument = node.arguments[0]\n if (argument === undefined || argument.type !== 'ObjectExpression') {\n return\n }\n\n const allProperties = argument.properties\n\n // no need to sort if there is at max 1 property\n if (allProperties.length < 2) {\n return\n }\n\n const properties = allProperties.flatMap((p) => {\n if (\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier\n ) {\n return { name: p.key.name, property: p }\n } else if (p.type === AST_NODE_TYPES.SpreadElement) {\n if (p.argument.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.name, property: p }\n } else {\n throw new Error('Unsupported spread element')\n }\n }\n return []\n })\n\n const sortedProperties = sortDataByOrder(properties, sortRules, 'name')\n if (sortedProperties === null) {\n return\n }\n context.report({\n node: argument,\n data: { function: node.callee.name },\n messageId: 'invalidOrder',\n fix(fixer) {\n const sourceCode = context.sourceCode\n\n const text = sortedProperties.reduce(\n (sourceText, specifier, index) => {\n let text = ''\n if (index < allProperties.length - 1) {\n text = sourceCode\n .getText()\n .slice(\n allProperties[index]!.range[1],\n allProperties[index + 1]!.range[0],\n )\n }\n return (\n sourceText + sourceCode.getText(specifier.property) + text\n )\n },\n '',\n )\n return fixer.replaceTextRange(\n [allProperties[0]!.range[0], allProperties.at(-1)!.range[1]],\n text,\n )\n },\n })\n },\n }\n }),\n})\n"],"names":["text"],"mappings":";;;;;AASA,MAAM,aAAa,YAAY,YAA2B,UAAU;AAEpE,MAAM,4BAA4B,IAAI,IAAI,sBAAsB;AAChE,SAAS,wBAAwB,MAA2C;AACnE,SAAA,0BAA0B,IAAI,IAAI;AAC3C;AAEO,MAAM,OAAO;AAEb,MAAM,OAAO,WAAW;AAAA,EAC7B;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,MACF,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,cAAc;AAAA,IAChB;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,gBAAgB;AAAA,IAChB,SAAS;AAAA,EACX;AAAA,EACA,gBAAgB,CAAC;AAAA,EAEjB,QAAQ,2BAA2B,CAAC,YAAY;AACvC,WAAA;AAAA,MACL,eAAe,MAAM;AACnB,YAAI,KAAK,OAAO,SAAS,eAAe,YAAY;AAClD;AAAA,QACF;AACM,cAAA,wBAAwB,KAAK,OAAO;AACtC,YAAA,CAAC,wBAAwB,qBAAqB,GAAG;AACnD;AAAA,QACF;AACM,cAAA,WAAW,KAAK,UAAU,CAAC;AACjC,YAAI,aAAa,UAAa,SAAS,SAAS,oBAAoB;AAClE;AAAA,QACF;AAEA,cAAM,gBAAgB,SAAS;AAG3B,YAAA,cAAc,SAAS,GAAG;AAC5B;AAAA,QACF;AAEA,cAAM,aAAa,cAAc,QAAQ,CAAC,MAAM;AAE5C,cAAA,EAAE,SAAS,eAAe,YAC1B,EAAE,IAAI,SAAS,eAAe,YAC9B;AACA,mBAAO,EAAE,MAAM,EAAE,IAAI,MAAM,UAAU;UAC5B,WAAA,EAAE,SAAS,eAAe,eAAe;AAClD,gBAAI,EAAE,SAAS,SAAS,eAAe,YAAY;AACjD,qBAAO,EAAE,MAAM,EAAE,SAAS,MAAM,UAAU;YAAE,OACvC;AACC,oBAAA,IAAI,MAAM,4BAA4B;AAAA,YAC9C;AAAA,UACF;AACA,iBAAO;QAAC,CACT;AAED,cAAM,mBAAmB,gBAAgB,YAAY,WAAW,MAAM;AACtE,YAAI,qBAAqB,MAAM;AAC7B;AAAA,QACF;AACA,gBAAQ,OAAO;AAAA,UACb,MAAM;AAAA,UACN,MAAM,EAAE,UAAU,KAAK,OAAO,KAAK;AAAA,UACnC,WAAW;AAAA,UACX,IAAI,OAAO;AACT,kBAAM,aAAa,QAAQ;AAE3B,kBAAM,OAAO,iBAAiB;AAAA,cAC5B,CAAC,YAAY,WAAW,UAAU;AAChC,oBAAIA,QAAO;AACP,oBAAA,QAAQ,cAAc,SAAS,GAAG;AACpCA,0BAAO,WACJ,QAAA,EACA;AAAA,oBACC,cAAc,KAAK,EAAG,MAAM,CAAC;AAAA,oBAC7B,cAAc,QAAQ,CAAC,EAAG,MAAM,CAAC;AAAA,kBAAA;AAAA,gBAEvC;AACA,uBACE,aAAa,WAAW,QAAQ,UAAU,QAAQ,IAAIA;AAAAA,cAE1D;AAAA,cACA;AAAA,YAAA;AAEF,mBAAO,MAAM;AAAA,cACX,CAAC,cAAc,CAAC,EAAG,MAAM,CAAC,GAAG,cAAc,GAAG,EAAE,EAAG,MAAM,CAAC,CAAC;AAAA,cAC3D;AAAA,YAAA;AAAA,UAEJ;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IAAA;AAAA,EACF,CACD;AACH,CAAC;"}
@@ -1 +1 @@
1
- export declare function sortDataByOrder<T, TKey extends keyof T>(data: Array<T> | ReadonlyArray<T>, orderArray: Array<T[TKey]> | ReadonlyArray<T[TKey]>, key: TKey): Array<T> | null;
1
+ export declare function sortDataByOrder<T, TKey extends keyof T>(data: Array<T> | ReadonlyArray<T>, orderRules: ReadonlyArray<Readonly<[ReadonlyArray<T[TKey]>, ReadonlyArray<T[TKey]>]>>, key: TKey): Array<T> | null;
@@ -1,14 +1,33 @@
1
- function sortDataByOrder(data, orderArray, key) {
2
- const orderMap = new Map(orderArray.map((item, index) => [item, index]));
3
- const inOrderArray = data.filter((item) => orderMap.has(item[key])).sort((a, b) => {
4
- const indexA = orderMap.get(a[key]);
5
- const indexB = orderMap.get(b[key]);
6
- return indexA - indexB;
7
- });
8
- const inOrderIterator = inOrderArray.values();
1
+ function sortDataByOrder(data, orderRules, key) {
2
+ const getSubsetIndex = (item, subsets) => {
3
+ var _a;
4
+ for (let i = 0; i < subsets.length; i++) {
5
+ if ((_a = subsets[i]) == null ? void 0 : _a.includes(item)) {
6
+ return i;
7
+ }
8
+ }
9
+ return null;
10
+ };
11
+ const orderSets = orderRules.reduce(
12
+ (sets, [A, B]) => [...sets, A, B],
13
+ []
14
+ );
15
+ const inOrderArray = data.filter(
16
+ (item) => getSubsetIndex(item[key], orderSets) !== null
17
+ );
9
18
  let wasResorted = false;
19
+ const sortedArray = inOrderArray.sort((a, b) => {
20
+ const aKey = a[key], bKey = b[key];
21
+ const aSubsetIndex = getSubsetIndex(aKey, orderSets);
22
+ const bSubsetIndex = getSubsetIndex(bKey, orderSets);
23
+ if (aSubsetIndex !== null && bSubsetIndex !== null && aSubsetIndex !== bSubsetIndex) {
24
+ return aSubsetIndex - bSubsetIndex;
25
+ }
26
+ return 0;
27
+ });
28
+ const inOrderIterator = sortedArray.values();
10
29
  const result = data.map((item) => {
11
- if (orderMap.has(item[key])) {
30
+ if (getSubsetIndex(item[key], orderSets) !== null) {
12
31
  const sortedItem = inOrderIterator.next().value;
13
32
  if (sortedItem[key] !== item[key]) {
14
33
  wasResorted = true;
@@ -1 +1 @@
1
- {"version":3,"file":"infinite-query-property-order.utils.js","sources":["../../../../src/rules/infinite-query-property-order/infinite-query-property-order.utils.ts"],"sourcesContent":["export function sortDataByOrder<T, TKey extends keyof T>(\n data: Array<T> | ReadonlyArray<T>,\n orderArray: Array<T[TKey]> | ReadonlyArray<T[TKey]>,\n key: TKey,\n): Array<T> | null {\n const orderMap = new Map(orderArray.map((item, index) => [item, index]))\n\n // Separate items that are in orderArray from those that are not\n const inOrderArray = data\n .filter((item) => orderMap.has(item[key]))\n .sort((a, b) => {\n const indexA = orderMap.get(a[key])!\n const indexB = orderMap.get(b[key])!\n\n return indexA - indexB\n })\n\n const inOrderIterator = inOrderArray.values()\n\n // `as boolean` is needed to avoid TS incorrectly inferring that wasResorted is always `true`\n let wasResorted = false as boolean\n\n const result = data.map((item) => {\n if (orderMap.has(item[key])) {\n const sortedItem = inOrderIterator.next().value!\n if (sortedItem[key] !== item[key]) {\n wasResorted = true\n }\n return sortedItem\n }\n return item\n })\n\n if (!wasResorted) {\n return null\n }\n return result\n}\n"],"names":[],"mappings":"AAAgB,SAAA,gBACd,MACA,YACA,KACiB;AACjB,QAAM,WAAW,IAAI,IAAI,WAAW,IAAI,CAAC,MAAM,UAAU,CAAC,MAAM,KAAK,CAAC,CAAC;AAGvE,QAAM,eAAe,KAClB,OAAO,CAAC,SAAS,SAAS,IAAI,KAAK,GAAG,CAAC,CAAC,EACxC,KAAK,CAAC,GAAG,MAAM;AACd,UAAM,SAAS,SAAS,IAAI,EAAE,GAAG,CAAC;AAClC,UAAM,SAAS,SAAS,IAAI,EAAE,GAAG,CAAC;AAElC,WAAO,SAAS;AAAA,EAAA,CACjB;AAEG,QAAA,kBAAkB,aAAa;AAGrC,MAAI,cAAc;AAElB,QAAM,SAAS,KAAK,IAAI,CAAC,SAAS;AAChC,QAAI,SAAS,IAAI,KAAK,GAAG,CAAC,GAAG;AACrB,YAAA,aAAa,gBAAgB,KAAA,EAAO;AAC1C,UAAI,WAAW,GAAG,MAAM,KAAK,GAAG,GAAG;AACnB,sBAAA;AAAA,MAChB;AACO,aAAA;AAAA,IACT;AACO,WAAA;AAAA,EAAA,CACR;AAED,MAAI,CAAC,aAAa;AACT,WAAA;AAAA,EACT;AACO,SAAA;AACT;"}
1
+ {"version":3,"file":"infinite-query-property-order.utils.js","sources":["../../../../src/rules/infinite-query-property-order/infinite-query-property-order.utils.ts"],"sourcesContent":["export function sortDataByOrder<T, TKey extends keyof T>(\n data: Array<T> | ReadonlyArray<T>,\n orderRules: ReadonlyArray<\n Readonly<[ReadonlyArray<T[TKey]>, ReadonlyArray<T[TKey]>]>\n >,\n key: TKey,\n): Array<T> | null {\n const getSubsetIndex = (\n item: T[TKey],\n subsets: ReadonlyArray<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,\n ): number | null => {\n for (let i = 0; i < subsets.length; i++) {\n if (subsets[i]?.includes(item)) {\n return i\n }\n }\n return null\n }\n\n const orderSets = orderRules.reduce(\n (sets, [A, B]) => [...sets, A, B],\n [] as Array<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,\n )\n\n const inOrderArray = data.filter(\n (item) => getSubsetIndex(item[key], orderSets) !== null,\n )\n\n let wasResorted = false as boolean\n\n // Sort by the relative order defined by the rules\n const sortedArray = inOrderArray.sort((a, b) => {\n const aKey = a[key],\n bKey = b[key]\n const aSubsetIndex = getSubsetIndex(aKey, orderSets)\n const bSubsetIndex = getSubsetIndex(bKey, orderSets)\n\n // If both items belong to different subsets, sort by their subset order\n if (\n aSubsetIndex !== null &&\n bSubsetIndex !== null &&\n aSubsetIndex !== bSubsetIndex\n ) {\n return aSubsetIndex - bSubsetIndex\n }\n\n // If both items belong to the same subset or neither is in the subset, keep their relative order\n return 0\n })\n\n const inOrderIterator = sortedArray.values()\n const result = data.map((item) => {\n if (getSubsetIndex(item[key], orderSets) !== null) {\n const sortedItem = inOrderIterator.next().value!\n if (sortedItem[key] !== item[key]) {\n wasResorted = true\n }\n return sortedItem\n }\n return item\n })\n\n if (!wasResorted) {\n return null\n }\n return result\n}\n"],"names":[],"mappings":"AAAgB,SAAA,gBACd,MACA,YAGA,KACiB;AACX,QAAA,iBAAiB,CACrB,MACA,YACkB;AAVN;AAWZ,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,WAAI,aAAQ,CAAC,MAAT,mBAAY,SAAS,OAAO;AACvB,eAAA;AAAA,MACT;AAAA,IACF;AACO,WAAA;AAAA,EAAA;AAGT,QAAM,YAAY,WAAW;AAAA,IAC3B,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC;AAAA,IAChC,CAAC;AAAA,EAAA;AAGH,QAAM,eAAe,KAAK;AAAA,IACxB,CAAC,SAAS,eAAe,KAAK,GAAG,GAAG,SAAS,MAAM;AAAA,EAAA;AAGrD,MAAI,cAAc;AAGlB,QAAM,cAAc,aAAa,KAAK,CAAC,GAAG,MAAM;AAC9C,UAAM,OAAO,EAAE,GAAG,GAChB,OAAO,EAAE,GAAG;AACR,UAAA,eAAe,eAAe,MAAM,SAAS;AAC7C,UAAA,eAAe,eAAe,MAAM,SAAS;AAGnD,QACE,iBAAiB,QACjB,iBAAiB,QACjB,iBAAiB,cACjB;AACA,aAAO,eAAe;AAAA,IACxB;AAGO,WAAA;AAAA,EAAA,CACR;AAEK,QAAA,kBAAkB,YAAY;AACpC,QAAM,SAAS,KAAK,IAAI,CAAC,SAAS;AAChC,QAAI,eAAe,KAAK,GAAG,GAAG,SAAS,MAAM,MAAM;AAC3C,YAAA,aAAa,gBAAgB,KAAA,EAAO;AAC1C,UAAI,WAAW,GAAG,MAAM,KAAK,GAAG,GAAG;AACnB,sBAAA;AAAA,MAChB;AACO,aAAA;AAAA,IACT;AACO,WAAA;AAAA,EAAA,CACR;AAED,MAAI,CAAC,aAAa;AACT,WAAA;AAAA,EACT;AACO,SAAA;AACT;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/eslint-plugin-query",
3
- "version": "5.57.0",
3
+ "version": "5.57.1",
4
4
  "description": "ESLint plugin for TanStack Query",
5
5
  "author": "Eliya Cohen",
6
6
  "license": "MIT",
@@ -32,18 +32,60 @@ const validTestMatrix = combinate({
32
32
  properties: generatePartialCombinations(checkedProperties, 2),
33
33
  })
34
34
 
35
- export function generateInvalidPermutations<T>(
36
- arr: ReadonlyArray<T>,
37
- ): Array<{ invalid: Array<T>; valid: Array<T> }> {
35
+ export function generateInvalidPermutations(
36
+ arr: ReadonlyArray<CheckedProperties>,
37
+ ): Array<{
38
+ invalid: Array<CheckedProperties>
39
+ valid: Array<CheckedProperties>
40
+ }> {
38
41
  const combinations = generatePartialCombinations(arr, 2)
39
- const allPermutations: Array<{ invalid: Array<T>; valid: Array<T> }> = []
42
+ const allPermutations: Array<{
43
+ invalid: Array<CheckedProperties>
44
+ valid: Array<CheckedProperties>
45
+ }> = []
40
46
 
41
47
  for (const combination of combinations) {
42
48
  const permutations = generatePermutations(combination)
43
49
  // skip the first permutation as it matches the original combination
44
50
  const invalidPermutations = permutations.slice(1)
51
+
52
+ if (
53
+ combination.includes('getNextPageParam') &&
54
+ combination.includes('getPreviousPageParam')
55
+ ) {
56
+ if (
57
+ combination.indexOf('getNextPageParam') <
58
+ combination.indexOf('getPreviousPageParam')
59
+ ) {
60
+ // since we ignore the relative order of 'getPreviousPageParam' and 'getNextPageParam', we skip this combination (but keep the other one where `getPreviousPageParam` is before `getNextPageParam`)
61
+
62
+ continue
63
+ }
64
+ }
65
+
45
66
  allPermutations.push(
46
- ...invalidPermutations.map((p) => ({ invalid: p, valid: combination })),
67
+ ...invalidPermutations
68
+ .map((p) => {
69
+ // ignore the relative order of 'getPreviousPageParam' and 'getNextPageParam'
70
+ const correctedValid = [...combination].sort((a, b) => {
71
+ if (
72
+ (a === 'getNextPageParam' && b === 'getPreviousPageParam') ||
73
+ (a === 'getPreviousPageParam' && b === 'getNextPageParam')
74
+ ) {
75
+ return p.indexOf(a) - p.indexOf(b)
76
+ }
77
+ return checkedProperties.indexOf(a) - checkedProperties.indexOf(b)
78
+ })
79
+ return { invalid: p, valid: correctedValid }
80
+ })
81
+ .filter(
82
+ ({ invalid }) =>
83
+ // if `getPreviousPageParam` and `getNextPageParam` are next to each other and `queryFn` is not present, we skip this invalid permutation
84
+ Math.abs(
85
+ invalid.indexOf('getNextPageParam') -
86
+ invalid.indexOf('getPreviousPageParam'),
87
+ ) !== 1 && !invalid.includes('queryFn'),
88
+ ),
47
89
  )
48
90
  }
49
91
 
@@ -121,7 +163,7 @@ const validTestCases = validTestMatrix.map(
121
163
 
122
164
  const invalidTestCases = invalidTestMatrix.map(
123
165
  ({ infiniteQueryFunction, properties }) => ({
124
- name: `incorrect property order is detected for ${infiniteQueryFunction} with order: ${properties.invalid.join(', ')}`,
166
+ name: `incorrect property order is detected for ${infiniteQueryFunction} with invalid order: ${properties.invalid.join(', ')}, valid order: ${properties.valid.join(', ')}`,
125
167
  code: getCode({
126
168
  infiniteQueryFunction: infiniteQueryFunction,
127
169
  properties: properties.invalid,
@@ -6,43 +6,64 @@ describe('create-route-property-order utils', () => {
6
6
  const testCases = [
7
7
  {
8
8
  data: [{ key: 'a' }, { key: 'c' }, { key: 'b' }],
9
- orderArray: ['a', 'b', 'c'],
9
+ orderArray: [
10
+ [['a'], ['b']],
11
+ [['b'], ['c']],
12
+ ],
10
13
  key: 'key',
11
14
  expected: [{ key: 'a' }, { key: 'b' }, { key: 'c' }],
12
15
  },
13
16
  {
14
17
  data: [{ key: 'b' }, { key: 'a' }, { key: 'c' }],
15
- orderArray: ['a', 'b', 'c'],
18
+ orderArray: [
19
+ [['a'], ['b']],
20
+ [['b'], ['c']],
21
+ ],
16
22
  key: 'key',
17
23
  expected: [{ key: 'a' }, { key: 'b' }, { key: 'c' }],
18
24
  },
19
25
  {
20
26
  data: [{ key: 'a' }, { key: 'b' }, { key: 'c' }],
21
- orderArray: ['a', 'b', 'c'],
27
+ orderArray: [
28
+ [['a'], ['b']],
29
+ [['b'], ['c']],
30
+ ],
22
31
  key: 'key',
23
32
  expected: null,
24
33
  },
25
34
  {
26
35
  data: [{ key: 'a' }, { key: 'b' }, { key: 'c' }, { key: 'd' }],
27
- orderArray: ['a', 'b', 'c'],
36
+ orderArray: [
37
+ [['a'], ['b']],
38
+ [['b'], ['c']],
39
+ ],
28
40
  key: 'key',
29
41
  expected: null,
30
42
  },
31
43
  {
32
44
  data: [{ key: 'a' }, { key: 'b' }, { key: 'd' }, { key: 'c' }],
33
- orderArray: ['a', 'b', 'c'],
45
+ orderArray: [
46
+ [['a'], ['b']],
47
+ [['b'], ['c']],
48
+ ],
34
49
  key: 'key',
35
50
  expected: null,
36
51
  },
37
52
  {
38
53
  data: [{ key: 'd' }, { key: 'a' }, { key: 'b' }, { key: 'c' }],
39
- orderArray: ['a', 'b', 'c'],
54
+ orderArray: [
55
+ [['a'], ['b']],
56
+ [['b'], ['c']],
57
+ ],
40
58
  key: 'key',
41
59
  expected: null,
42
60
  },
43
61
  {
44
62
  data: [{ key: 'd' }, { key: 'b' }, { key: 'a' }, { key: 'c' }],
45
- orderArray: ['a', 'b', 'c'],
63
+ orderArray: [
64
+ [['a'], ['b']],
65
+ [['b'], ['c']],
66
+ ],
46
67
  key: 'key',
47
68
  expected: [{ key: 'd' }, { key: 'a' }, { key: 'b' }, { key: 'c' }],
48
69
  },
@@ -11,3 +11,7 @@ export const checkedProperties = [
11
11
  'getPreviousPageParam',
12
12
  'getNextPageParam',
13
13
  ] as const
14
+
15
+ export const sortRules = [
16
+ [['queryFn'], ['getPreviousPageParam', 'getNextPageParam']],
17
+ ] as const
@@ -3,7 +3,7 @@ import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'
3
3
  import { getDocsUrl } from '../../utils/get-docs-url'
4
4
  import { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'
5
5
  import { sortDataByOrder } from './infinite-query-property-order.utils'
6
- import { checkedProperties, infiniteQueryFunctions } from './constants'
6
+ import { infiniteQueryFunctions, sortRules } from './constants'
7
7
  import type { InfiniteQueryFunctions } from './constants'
8
8
  import type { ExtraRuleDocs } from '../../types'
9
9
 
@@ -50,6 +50,8 @@ export const rule = createRule({
50
50
  }
51
51
 
52
52
  const allProperties = argument.properties
53
+
54
+ // no need to sort if there is at max 1 property
53
55
  if (allProperties.length < 2) {
54
56
  return
55
57
  }
@@ -70,11 +72,7 @@ export const rule = createRule({
70
72
  return []
71
73
  })
72
74
 
73
- const sortedProperties = sortDataByOrder(
74
- properties,
75
- checkedProperties,
76
- 'name',
77
- )
75
+ const sortedProperties = sortDataByOrder(properties, sortRules, 'name')
78
76
  if (sortedProperties === null) {
79
77
  return
80
78
  }
@@ -1,27 +1,56 @@
1
1
  export function sortDataByOrder<T, TKey extends keyof T>(
2
2
  data: Array<T> | ReadonlyArray<T>,
3
- orderArray: Array<T[TKey]> | ReadonlyArray<T[TKey]>,
3
+ orderRules: ReadonlyArray<
4
+ Readonly<[ReadonlyArray<T[TKey]>, ReadonlyArray<T[TKey]>]>
5
+ >,
4
6
  key: TKey,
5
7
  ): Array<T> | null {
6
- const orderMap = new Map(orderArray.map((item, index) => [item, index]))
7
-
8
- // Separate items that are in orderArray from those that are not
9
- const inOrderArray = data
10
- .filter((item) => orderMap.has(item[key]))
11
- .sort((a, b) => {
12
- const indexA = orderMap.get(a[key])!
13
- const indexB = orderMap.get(b[key])!
8
+ const getSubsetIndex = (
9
+ item: T[TKey],
10
+ subsets: ReadonlyArray<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,
11
+ ): number | null => {
12
+ for (let i = 0; i < subsets.length; i++) {
13
+ if (subsets[i]?.includes(item)) {
14
+ return i
15
+ }
16
+ }
17
+ return null
18
+ }
14
19
 
15
- return indexA - indexB
16
- })
20
+ const orderSets = orderRules.reduce(
21
+ (sets, [A, B]) => [...sets, A, B],
22
+ [] as Array<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,
23
+ )
17
24
 
18
- const inOrderIterator = inOrderArray.values()
25
+ const inOrderArray = data.filter(
26
+ (item) => getSubsetIndex(item[key], orderSets) !== null,
27
+ )
19
28
 
20
- // `as boolean` is needed to avoid TS incorrectly inferring that wasResorted is always `true`
21
29
  let wasResorted = false as boolean
22
30
 
31
+ // Sort by the relative order defined by the rules
32
+ const sortedArray = inOrderArray.sort((a, b) => {
33
+ const aKey = a[key],
34
+ bKey = b[key]
35
+ const aSubsetIndex = getSubsetIndex(aKey, orderSets)
36
+ const bSubsetIndex = getSubsetIndex(bKey, orderSets)
37
+
38
+ // If both items belong to different subsets, sort by their subset order
39
+ if (
40
+ aSubsetIndex !== null &&
41
+ bSubsetIndex !== null &&
42
+ aSubsetIndex !== bSubsetIndex
43
+ ) {
44
+ return aSubsetIndex - bSubsetIndex
45
+ }
46
+
47
+ // If both items belong to the same subset or neither is in the subset, keep their relative order
48
+ return 0
49
+ })
50
+
51
+ const inOrderIterator = sortedArray.values()
23
52
  const result = data.map((item) => {
24
- if (orderMap.has(item[key])) {
53
+ if (getSubsetIndex(item[key], orderSets) !== null) {
25
54
  const sortedItem = inOrderIterator.next().value!
26
55
  if (sortedItem[key] !== item[key]) {
27
56
  wasResorted = true