@tanstack/eslint-plugin-query 5.56.1 → 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.
- package/dist/cjs/index.cjs +4 -2
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/rules/infinite-query-property-order/constants.cjs +13 -0
- package/dist/cjs/rules/infinite-query-property-order/constants.cjs.map +1 -0
- package/dist/cjs/rules/infinite-query-property-order/constants.d.cts +4 -0
- package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.rule.cjs +95 -0
- package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.rule.cjs.map +1 -0
- package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.rule.d.cts +4 -0
- package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.utils.cjs +47 -0
- package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.utils.cjs.map +1 -0
- package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.utils.d.cts +1 -0
- package/dist/cjs/rules/no-unstable-deps/no-unstable-deps.rule.cjs +1 -1
- package/dist/cjs/rules/no-unstable-deps/no-unstable-deps.rule.cjs.map +1 -1
- package/dist/cjs/rules.cjs +3 -1
- package/dist/cjs/rules.cjs.map +1 -1
- package/dist/esm/index.js +4 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/rules/infinite-query-property-order/constants.d.ts +4 -0
- package/dist/esm/rules/infinite-query-property-order/constants.js +13 -0
- package/dist/esm/rules/infinite-query-property-order/constants.js.map +1 -0
- package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.rule.d.ts +4 -0
- package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.rule.js +95 -0
- package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.rule.js.map +1 -0
- package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.utils.d.ts +1 -0
- package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.utils.js +47 -0
- package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.utils.js.map +1 -0
- package/dist/esm/rules/no-unstable-deps/no-unstable-deps.rule.js +1 -1
- package/dist/esm/rules/no-unstable-deps/no-unstable-deps.rule.js.map +1 -1
- package/dist/esm/rules.js +3 -1
- package/dist/esm/rules.js.map +1 -1
- package/package.json +2 -1
- package/src/__tests__/infinite-query-property-order.rule.test.ts +182 -0
- package/src/__tests__/infinite-query-property-order.utils.test.ts +79 -0
- package/src/__tests__/test-utils.test.ts +104 -0
- package/src/__tests__/test-utils.ts +103 -0
- package/src/index.ts +2 -0
- package/src/rules/infinite-query-property-order/constants.ts +17 -0
- package/src/rules/infinite-query-property-order/infinite-query-property-order.rule.ts +112 -0
- package/src/rules/infinite-query-property-order/infinite-query-property-order.utils.ts +67 -0
- package/src/rules/no-unstable-deps/no-unstable-deps.rule.ts +1 -1
- package/src/rules.ts +2 -0
package/dist/cjs/index.cjs
CHANGED
|
@@ -14,7 +14,8 @@ Object.assign(plugin.configs, {
|
|
|
14
14
|
"@tanstack/query/exhaustive-deps": "error",
|
|
15
15
|
"@tanstack/query/no-rest-destructuring": "warn",
|
|
16
16
|
"@tanstack/query/stable-query-client": "error",
|
|
17
|
-
"@tanstack/query/no-unstable-deps": "error"
|
|
17
|
+
"@tanstack/query/no-unstable-deps": "error",
|
|
18
|
+
"@tanstack/query/infinite-query-property-order": "error"
|
|
18
19
|
}
|
|
19
20
|
},
|
|
20
21
|
"flat/recommended": [
|
|
@@ -26,7 +27,8 @@ Object.assign(plugin.configs, {
|
|
|
26
27
|
"@tanstack/query/exhaustive-deps": "error",
|
|
27
28
|
"@tanstack/query/no-rest-destructuring": "warn",
|
|
28
29
|
"@tanstack/query/stable-query-client": "error",
|
|
29
|
-
"@tanstack/query/no-unstable-deps": "error"
|
|
30
|
+
"@tanstack/query/no-unstable-deps": "error",
|
|
31
|
+
"@tanstack/query/infinite-query-property-order": "error"
|
|
30
32
|
}
|
|
31
33
|
}
|
|
32
34
|
]
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import { rules } from './rules'\nimport type { ESLint, Linter } from 'eslint'\nimport type { RuleModule } from '@typescript-eslint/utils/ts-eslint'\n\ntype RuleKey = keyof typeof rules\n\ninterface Plugin extends Omit<ESLint.Plugin, 'rules'> {\n rules: Record<RuleKey, RuleModule<any, any, any>>\n configs: {\n recommended: ESLint.ConfigData\n 'flat/recommended': Array<Linter.FlatConfig>\n }\n}\n\nconst plugin: Plugin = {\n meta: {\n name: '@tanstack/eslint-plugin-query',\n },\n configs: {} as Plugin['configs'],\n rules,\n}\n\n// Assign configs here so we can reference `plugin`\nObject.assign(plugin.configs, {\n recommended: {\n plugins: ['@tanstack/eslint-plugin-query'],\n rules: {\n '@tanstack/query/exhaustive-deps': 'error',\n '@tanstack/query/no-rest-destructuring': 'warn',\n '@tanstack/query/stable-query-client': 'error',\n '@tanstack/query/no-unstable-deps': 'error',\n },\n },\n 'flat/recommended': [\n {\n plugins: {\n '@tanstack/query': plugin,\n },\n rules: {\n '@tanstack/query/exhaustive-deps': 'error',\n '@tanstack/query/no-rest-destructuring': 'warn',\n '@tanstack/query/stable-query-client': 'error',\n '@tanstack/query/no-unstable-deps': 'error',\n },\n },\n ],\n})\n\nexport default plugin\n"],"names":["rules"],"mappings":";;AAcA,MAAM,SAAiB;AAAA,EACrB,MAAM;AAAA,IACJ,MAAM;AAAA,EACR;AAAA,EACA,SAAS,CAAC;AAAA,EAAA,OACVA,MAAA;AACF;AAGA,OAAO,OAAO,OAAO,SAAS;AAAA,EAC5B,aAAa;AAAA,IACX,SAAS,CAAC,+BAA+B;AAAA,IACzC,OAAO;AAAA,MACL,mCAAmC;AAAA,MACnC,yCAAyC;AAAA,MACzC,uCAAuC;AAAA,MACvC,oCAAoC;AAAA,
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import { rules } from './rules'\nimport type { ESLint, Linter } from 'eslint'\nimport type { RuleModule } from '@typescript-eslint/utils/ts-eslint'\n\ntype RuleKey = keyof typeof rules\n\ninterface Plugin extends Omit<ESLint.Plugin, 'rules'> {\n rules: Record<RuleKey, RuleModule<any, any, any>>\n configs: {\n recommended: ESLint.ConfigData\n 'flat/recommended': Array<Linter.FlatConfig>\n }\n}\n\nconst plugin: Plugin = {\n meta: {\n name: '@tanstack/eslint-plugin-query',\n },\n configs: {} as Plugin['configs'],\n rules,\n}\n\n// Assign configs here so we can reference `plugin`\nObject.assign(plugin.configs, {\n recommended: {\n plugins: ['@tanstack/eslint-plugin-query'],\n rules: {\n '@tanstack/query/exhaustive-deps': 'error',\n '@tanstack/query/no-rest-destructuring': 'warn',\n '@tanstack/query/stable-query-client': 'error',\n '@tanstack/query/no-unstable-deps': 'error',\n '@tanstack/query/infinite-query-property-order': 'error',\n },\n },\n 'flat/recommended': [\n {\n plugins: {\n '@tanstack/query': plugin,\n },\n rules: {\n '@tanstack/query/exhaustive-deps': 'error',\n '@tanstack/query/no-rest-destructuring': 'warn',\n '@tanstack/query/stable-query-client': 'error',\n '@tanstack/query/no-unstable-deps': 'error',\n '@tanstack/query/infinite-query-property-order': 'error',\n },\n },\n ],\n})\n\nexport default plugin\n"],"names":["rules"],"mappings":";;AAcA,MAAM,SAAiB;AAAA,EACrB,MAAM;AAAA,IACJ,MAAM;AAAA,EACR;AAAA,EACA,SAAS,CAAC;AAAA,EAAA,OACVA,MAAA;AACF;AAGA,OAAO,OAAO,OAAO,SAAS;AAAA,EAC5B,aAAa;AAAA,IACX,SAAS,CAAC,+BAA+B;AAAA,IACzC,OAAO;AAAA,MACL,mCAAmC;AAAA,MACnC,yCAAyC;AAAA,MACzC,uCAAuC;AAAA,MACvC,oCAAoC;AAAA,MACpC,iDAAiD;AAAA,IACnD;AAAA,EACF;AAAA,EACA,oBAAoB;AAAA,IAClB;AAAA,MACE,SAAS;AAAA,QACP,mBAAmB;AAAA,MACrB;AAAA,MACA,OAAO;AAAA,QACL,mCAAmC;AAAA,QACnC,yCAAyC;AAAA,QACzC,uCAAuC;AAAA,QACvC,oCAAoC;AAAA,QACpC,iDAAiD;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AACF,CAAC;;"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const infiniteQueryFunctions = [
|
|
4
|
+
"infiniteQueryOptions",
|
|
5
|
+
"useInfiniteQuery",
|
|
6
|
+
"useSuspenseInfiniteQuery"
|
|
7
|
+
];
|
|
8
|
+
const sortRules = [
|
|
9
|
+
[["queryFn"], ["getPreviousPageParam", "getNextPageParam"]]
|
|
10
|
+
];
|
|
11
|
+
exports.infiniteQueryFunctions = infiniteQueryFunctions;
|
|
12
|
+
exports.sortRules = sortRules;
|
|
13
|
+
//# sourceMappingURL=constants.cjs.map
|
|
@@ -0,0 +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\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;;;"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const infiniteQueryFunctions: readonly ["infiniteQueryOptions", "useInfiniteQuery", "useSuspenseInfiniteQuery"];
|
|
2
|
+
export type InfiniteQueryFunctions = (typeof infiniteQueryFunctions)[number];
|
|
3
|
+
export declare const checkedProperties: readonly ["queryFn", "getPreviousPageParam", "getNextPageParam"];
|
|
4
|
+
export declare const sortRules: readonly [readonly [readonly ["queryFn"], readonly ["getPreviousPageParam", "getNextPageParam"]]];
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const utils = require("@typescript-eslint/utils");
|
|
4
|
+
const getDocsUrl = require("../../utils/get-docs-url.cjs");
|
|
5
|
+
const detectReactQueryImports = require("../../utils/detect-react-query-imports.cjs");
|
|
6
|
+
const infiniteQueryPropertyOrder_utils = require("./infinite-query-property-order.utils.cjs");
|
|
7
|
+
const constants = require("./constants.cjs");
|
|
8
|
+
const createRule = utils.ESLintUtils.RuleCreator(getDocsUrl.getDocsUrl);
|
|
9
|
+
const infiniteQueryFunctionsSet = new Set(constants.infiniteQueryFunctions);
|
|
10
|
+
function isInfiniteQueryFunction(node) {
|
|
11
|
+
return infiniteQueryFunctionsSet.has(node);
|
|
12
|
+
}
|
|
13
|
+
const name = "infinite-query-property-order";
|
|
14
|
+
const rule = createRule({
|
|
15
|
+
name,
|
|
16
|
+
meta: {
|
|
17
|
+
type: "problem",
|
|
18
|
+
docs: {
|
|
19
|
+
description: "Ensure correct order of inference sensitive properties for infinite queries",
|
|
20
|
+
recommended: "error"
|
|
21
|
+
},
|
|
22
|
+
messages: {
|
|
23
|
+
invalidOrder: "Invalid order of properties for `{{function}}`."
|
|
24
|
+
},
|
|
25
|
+
schema: [],
|
|
26
|
+
hasSuggestions: true,
|
|
27
|
+
fixable: "code"
|
|
28
|
+
},
|
|
29
|
+
defaultOptions: [],
|
|
30
|
+
create: detectReactQueryImports.detectTanstackQueryImports((context) => {
|
|
31
|
+
return {
|
|
32
|
+
CallExpression(node) {
|
|
33
|
+
if (node.callee.type !== utils.AST_NODE_TYPES.Identifier) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const infiniteQueryFunction = node.callee.name;
|
|
37
|
+
if (!isInfiniteQueryFunction(infiniteQueryFunction)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const argument = node.arguments[0];
|
|
41
|
+
if (argument === void 0 || argument.type !== "ObjectExpression") {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const allProperties = argument.properties;
|
|
45
|
+
if (allProperties.length < 2) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const properties = allProperties.flatMap((p) => {
|
|
49
|
+
if (p.type === utils.AST_NODE_TYPES.Property && p.key.type === utils.AST_NODE_TYPES.Identifier) {
|
|
50
|
+
return { name: p.key.name, property: p };
|
|
51
|
+
} else if (p.type === utils.AST_NODE_TYPES.SpreadElement) {
|
|
52
|
+
if (p.argument.type === utils.AST_NODE_TYPES.Identifier) {
|
|
53
|
+
return { name: p.argument.name, property: p };
|
|
54
|
+
} else {
|
|
55
|
+
throw new Error("Unsupported spread element");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return [];
|
|
59
|
+
});
|
|
60
|
+
const sortedProperties = infiniteQueryPropertyOrder_utils.sortDataByOrder(properties, constants.sortRules, "name");
|
|
61
|
+
if (sortedProperties === null) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
context.report({
|
|
65
|
+
node: argument,
|
|
66
|
+
data: { function: node.callee.name },
|
|
67
|
+
messageId: "invalidOrder",
|
|
68
|
+
fix(fixer) {
|
|
69
|
+
const sourceCode = context.sourceCode;
|
|
70
|
+
const text = sortedProperties.reduce(
|
|
71
|
+
(sourceText, specifier, index) => {
|
|
72
|
+
let text2 = "";
|
|
73
|
+
if (index < allProperties.length - 1) {
|
|
74
|
+
text2 = sourceCode.getText().slice(
|
|
75
|
+
allProperties[index].range[1],
|
|
76
|
+
allProperties[index + 1].range[0]
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
return sourceText + sourceCode.getText(specifier.property) + text2;
|
|
80
|
+
},
|
|
81
|
+
""
|
|
82
|
+
);
|
|
83
|
+
return fixer.replaceTextRange(
|
|
84
|
+
[allProperties[0].range[0], allProperties.at(-1).range[1]],
|
|
85
|
+
text
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
})
|
|
92
|
+
});
|
|
93
|
+
exports.name = name;
|
|
94
|
+
exports.rule = rule;
|
|
95
|
+
//# sourceMappingURL=infinite-query-property-order.rule.cjs.map
|
package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.rule.cjs.map
ADDED
|
@@ -0,0 +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 { 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;;;"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
import { ExtraRuleDocs } from '../../types';
|
|
3
|
+
export declare const name = "infinite-query-property-order";
|
|
4
|
+
export declare const rule: ESLintUtils.RuleModule<string, readonly unknown[], ExtraRuleDocs, ESLintUtils.RuleListener>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
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
|
+
);
|
|
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();
|
|
31
|
+
const result = data.map((item) => {
|
|
32
|
+
if (getSubsetIndex(item[key], orderSets) !== null) {
|
|
33
|
+
const sortedItem = inOrderIterator.next().value;
|
|
34
|
+
if (sortedItem[key] !== item[key]) {
|
|
35
|
+
wasResorted = true;
|
|
36
|
+
}
|
|
37
|
+
return sortedItem;
|
|
38
|
+
}
|
|
39
|
+
return item;
|
|
40
|
+
});
|
|
41
|
+
if (!wasResorted) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
|
46
|
+
exports.sortDataByOrder = sortDataByOrder;
|
|
47
|
+
//# sourceMappingURL=infinite-query-property-order.utils.cjs.map
|
package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.utils.cjs.map
ADDED
|
@@ -0,0 +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 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;;"}
|
package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.utils.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
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;
|
|
@@ -20,7 +20,7 @@ const rule = createRule({
|
|
|
20
20
|
meta: {
|
|
21
21
|
type: "problem",
|
|
22
22
|
docs: {
|
|
23
|
-
description: "Disallow putting the result of
|
|
23
|
+
description: "Disallow putting the result of query hooks directly in a React hook dependency array",
|
|
24
24
|
recommended: "error"
|
|
25
25
|
},
|
|
26
26
|
messages: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-unstable-deps.rule.cjs","sources":["../../../../src/rules/no-unstable-deps/no-unstable-deps.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'\nimport type { TSESTree } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from '../../types'\n\nexport const name = 'no-unstable-deps'\n\nexport const reactHookNames = ['useEffect', 'useCallback', 'useMemo']\nexport const useQueryHookNames = [\n 'useQuery',\n 'useSuspenseQuery',\n 'useQueries',\n 'useSuspenseQueries',\n 'useInfiniteQuery',\n 'useSuspenseInfiniteQuery',\n]\nconst allHookNames = ['useMutation', ...useQueryHookNames]\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow putting the result of
|
|
1
|
+
{"version":3,"file":"no-unstable-deps.rule.cjs","sources":["../../../../src/rules/no-unstable-deps/no-unstable-deps.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'\nimport type { TSESTree } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from '../../types'\n\nexport const name = 'no-unstable-deps'\n\nexport const reactHookNames = ['useEffect', 'useCallback', 'useMemo']\nexport const useQueryHookNames = [\n 'useQuery',\n 'useSuspenseQuery',\n 'useQueries',\n 'useSuspenseQueries',\n 'useInfiniteQuery',\n 'useSuspenseInfiniteQuery',\n]\nconst allHookNames = ['useMutation', ...useQueryHookNames]\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow putting the result of query hooks directly in a React hook dependency array',\n recommended: 'error',\n },\n messages: {\n noUnstableDeps: `The result of {{queryHook}} is not referentially stable, so don't pass it directly into the dependencies array of {{reactHook}}. Instead, destructure the return value of {{queryHook}} and pass the destructured values into the dependency array of {{reactHook}}.`,\n },\n schema: [],\n },\n defaultOptions: [],\n\n create: detectTanstackQueryImports((context) => {\n const trackedVariables: Record<string, string> = {}\n const hookAliasMap: Record<string, string> = {}\n\n function getReactHook(node: TSESTree.CallExpression): string | undefined {\n if (node.callee.type === 'Identifier') {\n const calleeName = node.callee.name\n // Check if the identifier is a known React hook or an alias\n if (reactHookNames.includes(calleeName) || calleeName in hookAliasMap) {\n return calleeName\n }\n } else if (\n node.callee.type === 'MemberExpression' &&\n node.callee.object.type === 'Identifier' &&\n node.callee.object.name === 'React' &&\n node.callee.property.type === 'Identifier' &&\n reactHookNames.includes(node.callee.property.name)\n ) {\n // Member expression case: `React.useCallback`\n return node.callee.property.name\n }\n return undefined\n }\n\n function collectVariableNames(\n pattern: TSESTree.BindingName,\n queryHook: string,\n ) {\n if (pattern.type === AST_NODE_TYPES.Identifier) {\n trackedVariables[pattern.name] = queryHook\n }\n }\n\n return {\n ImportDeclaration(node: TSESTree.ImportDeclaration) {\n if (\n node.specifiers.length > 0 &&\n node.importKind === 'value' &&\n node.source.value === 'React'\n ) {\n node.specifiers.forEach((specifier) => {\n if (\n specifier.type === AST_NODE_TYPES.ImportSpecifier &&\n reactHookNames.includes(specifier.imported.name)\n ) {\n // Track alias or direct import\n hookAliasMap[specifier.local.name] = specifier.imported.name\n }\n })\n }\n },\n\n VariableDeclarator(node) {\n if (\n node.init !== null &&\n node.init.type === AST_NODE_TYPES.CallExpression &&\n node.init.callee.type === AST_NODE_TYPES.Identifier &&\n allHookNames.includes(node.init.callee.name)\n ) {\n collectVariableNames(node.id, node.init.callee.name)\n }\n },\n CallExpression: (node) => {\n const reactHook = getReactHook(node)\n if (\n reactHook !== undefined &&\n node.arguments.length > 1 &&\n node.arguments[1]?.type === AST_NODE_TYPES.ArrayExpression\n ) {\n const depsArray = node.arguments[1].elements\n depsArray.forEach((dep) => {\n if (\n dep !== null &&\n dep.type === AST_NODE_TYPES.Identifier &&\n trackedVariables[dep.name] !== undefined\n ) {\n const queryHook = trackedVariables[dep.name]\n context.report({\n node: dep,\n messageId: 'noUnstableDeps',\n data: {\n queryHook,\n reactHook,\n },\n })\n }\n })\n }\n },\n }\n }),\n})\n"],"names":["ESLintUtils","getDocsUrl","detectTanstackQueryImports","AST_NODE_TYPES"],"mappings":";;;;;AAMO,MAAM,OAAO;AAEb,MAAM,iBAAiB,CAAC,aAAa,eAAe,SAAS;AAC7D,MAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACA,MAAM,eAAe,CAAC,eAAe,GAAG,iBAAiB;AACzD,MAAM,aAAaA,MAAY,YAAA,YAA2BC,WAAAA,UAAU;AAE7D,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,gBAAgB;AAAA,IAClB;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAAA,EACA,gBAAgB,CAAC;AAAA,EAEjB,QAAQC,wBAAAA,2BAA2B,CAAC,YAAY;AAC9C,UAAM,mBAA2C,CAAA;AACjD,UAAM,eAAuC,CAAA;AAE7C,aAAS,aAAa,MAAmD;AACnE,UAAA,KAAK,OAAO,SAAS,cAAc;AAC/B,cAAA,aAAa,KAAK,OAAO;AAE/B,YAAI,eAAe,SAAS,UAAU,KAAK,cAAc,cAAc;AAC9D,iBAAA;AAAA,QACT;AAAA,MACF,WACE,KAAK,OAAO,SAAS,sBACrB,KAAK,OAAO,OAAO,SAAS,gBAC5B,KAAK,OAAO,OAAO,SAAS,WAC5B,KAAK,OAAO,SAAS,SAAS,gBAC9B,eAAe,SAAS,KAAK,OAAO,SAAS,IAAI,GACjD;AAEO,eAAA,KAAK,OAAO,SAAS;AAAA,MAC9B;AACO,aAAA;AAAA,IACT;AAES,aAAA,qBACP,SACA,WACA;AACI,UAAA,QAAQ,SAASC,MAAA,eAAe,YAAY;AAC7B,yBAAA,QAAQ,IAAI,IAAI;AAAA,MACnC;AAAA,IACF;AAEO,WAAA;AAAA,MACL,kBAAkB,MAAkC;AAEhD,YAAA,KAAK,WAAW,SAAS,KACzB,KAAK,eAAe,WACpB,KAAK,OAAO,UAAU,SACtB;AACK,eAAA,WAAW,QAAQ,CAAC,cAAc;AAEnC,gBAAA,UAAU,SAASA,MAAAA,eAAe,mBAClC,eAAe,SAAS,UAAU,SAAS,IAAI,GAC/C;AAEA,2BAAa,UAAU,MAAM,IAAI,IAAI,UAAU,SAAS;AAAA,YAC1D;AAAA,UAAA,CACD;AAAA,QACH;AAAA,MACF;AAAA,MAEA,mBAAmB,MAAM;AAErB,YAAA,KAAK,SAAS,QACd,KAAK,KAAK,SAASA,MAAAA,eAAe,kBAClC,KAAK,KAAK,OAAO,SAASA,qBAAe,cACzC,aAAa,SAAS,KAAK,KAAK,OAAO,IAAI,GAC3C;AACA,+BAAqB,KAAK,IAAI,KAAK,KAAK,OAAO,IAAI;AAAA,QACrD;AAAA,MACF;AAAA,MACA,gBAAgB,CAAC,SAAS;;AAClB,cAAA,YAAY,aAAa,IAAI;AACnC,YACE,cAAc,UACd,KAAK,UAAU,SAAS,OACxB,UAAK,UAAU,CAAC,MAAhB,mBAAmB,UAASA,MAAAA,eAAe,iBAC3C;AACA,gBAAM,YAAY,KAAK,UAAU,CAAC,EAAE;AAC1B,oBAAA,QAAQ,CAAC,QAAQ;AAEvB,gBAAA,QAAQ,QACR,IAAI,SAASA,MAAA,eAAe,cAC5B,iBAAiB,IAAI,IAAI,MAAM,QAC/B;AACM,oBAAA,YAAY,iBAAiB,IAAI,IAAI;AAC3C,sBAAQ,OAAO;AAAA,gBACb,MAAM;AAAA,gBACN,WAAW;AAAA,gBACX,MAAM;AAAA,kBACJ;AAAA,kBACA;AAAA,gBACF;AAAA,cAAA,CACD;AAAA,YACH;AAAA,UAAA,CACD;AAAA,QACH;AAAA,MACF;AAAA,IAAA;AAAA,EACF,CACD;AACH,CAAC;;;;;"}
|
package/dist/cjs/rules.cjs
CHANGED
|
@@ -4,11 +4,13 @@ const exhaustiveDeps_rule = require("./rules/exhaustive-deps/exhaustive-deps.rul
|
|
|
4
4
|
const stableQueryClient_rule = require("./rules/stable-query-client/stable-query-client.rule.cjs");
|
|
5
5
|
const noRestDestructuring_rule = require("./rules/no-rest-destructuring/no-rest-destructuring.rule.cjs");
|
|
6
6
|
const noUnstableDeps_rule = require("./rules/no-unstable-deps/no-unstable-deps.rule.cjs");
|
|
7
|
+
const infiniteQueryPropertyOrder_rule = require("./rules/infinite-query-property-order/infinite-query-property-order.rule.cjs");
|
|
7
8
|
const rules = {
|
|
8
9
|
[exhaustiveDeps_rule.name]: exhaustiveDeps_rule.rule,
|
|
9
10
|
[stableQueryClient_rule.name]: stableQueryClient_rule.rule,
|
|
10
11
|
[noRestDestructuring_rule.name]: noRestDestructuring_rule.rule,
|
|
11
|
-
[noUnstableDeps_rule.name]: noUnstableDeps_rule.rule
|
|
12
|
+
[noUnstableDeps_rule.name]: noUnstableDeps_rule.rule,
|
|
13
|
+
[infiniteQueryPropertyOrder_rule.name]: infiniteQueryPropertyOrder_rule.rule
|
|
12
14
|
};
|
|
13
15
|
exports.rules = rules;
|
|
14
16
|
//# sourceMappingURL=rules.cjs.map
|
package/dist/cjs/rules.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.cjs","sources":["../../src/rules.ts"],"sourcesContent":["import * as exhaustiveDeps from './rules/exhaustive-deps/exhaustive-deps.rule'\nimport * as stableQueryClient from './rules/stable-query-client/stable-query-client.rule'\nimport * as noRestDestructuring from './rules/no-rest-destructuring/no-rest-destructuring.rule'\nimport * as noUnstableDeps from './rules/no-unstable-deps/no-unstable-deps.rule'\nimport type { ESLintUtils } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from './types'\n\nexport const rules: Record<\n string,\n ESLintUtils.RuleModule<\n string,\n ReadonlyArray<unknown>,\n ExtraRuleDocs,\n ESLintUtils.RuleListener\n >\n> = {\n [exhaustiveDeps.name]: exhaustiveDeps.rule,\n [stableQueryClient.name]: stableQueryClient.rule,\n [noRestDestructuring.name]: noRestDestructuring.rule,\n [noUnstableDeps.name]: noUnstableDeps.rule,\n}\n"],"names":["exhaustiveDeps.name","exhaustiveDeps.rule","stableQueryClient.name","stableQueryClient.rule","noRestDestructuring.name","noRestDestructuring.rule","noUnstableDeps.name","noUnstableDeps.rule"],"mappings":"
|
|
1
|
+
{"version":3,"file":"rules.cjs","sources":["../../src/rules.ts"],"sourcesContent":["import * as exhaustiveDeps from './rules/exhaustive-deps/exhaustive-deps.rule'\nimport * as stableQueryClient from './rules/stable-query-client/stable-query-client.rule'\nimport * as noRestDestructuring from './rules/no-rest-destructuring/no-rest-destructuring.rule'\nimport * as noUnstableDeps from './rules/no-unstable-deps/no-unstable-deps.rule'\nimport * as infiniteQueryPropertyOrder from './rules/infinite-query-property-order/infinite-query-property-order.rule'\nimport type { ESLintUtils } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from './types'\n\nexport const rules: Record<\n string,\n ESLintUtils.RuleModule<\n string,\n ReadonlyArray<unknown>,\n ExtraRuleDocs,\n ESLintUtils.RuleListener\n >\n> = {\n [exhaustiveDeps.name]: exhaustiveDeps.rule,\n [stableQueryClient.name]: stableQueryClient.rule,\n [noRestDestructuring.name]: noRestDestructuring.rule,\n [noUnstableDeps.name]: noUnstableDeps.rule,\n [infiniteQueryPropertyOrder.name]: infiniteQueryPropertyOrder.rule,\n}\n"],"names":["exhaustiveDeps.name","exhaustiveDeps.rule","stableQueryClient.name","stableQueryClient.rule","noRestDestructuring.name","noRestDestructuring.rule","noUnstableDeps.name","noUnstableDeps.rule","infiniteQueryPropertyOrder.name","infiniteQueryPropertyOrder.rule"],"mappings":";;;;;;;AAQO,MAAM,QAQT;AAAA,EACF,CAACA,oBAAmB,IAAA,GAAGC,oBAAe;AAAA,EACtC,CAACC,uBAAsB,IAAA,GAAGC,uBAAkB;AAAA,EAC5C,CAACC,yBAAwB,IAAA,GAAGC,yBAAoB;AAAA,EAChD,CAACC,oBAAmB,IAAA,GAAGC,oBAAe;AAAA,EACtC,CAACC,gCAA+B,IAAA,GAAGC,gCAA2B;AAChE;;"}
|
package/dist/esm/index.js
CHANGED
|
@@ -13,7 +13,8 @@ Object.assign(plugin.configs, {
|
|
|
13
13
|
"@tanstack/query/exhaustive-deps": "error",
|
|
14
14
|
"@tanstack/query/no-rest-destructuring": "warn",
|
|
15
15
|
"@tanstack/query/stable-query-client": "error",
|
|
16
|
-
"@tanstack/query/no-unstable-deps": "error"
|
|
16
|
+
"@tanstack/query/no-unstable-deps": "error",
|
|
17
|
+
"@tanstack/query/infinite-query-property-order": "error"
|
|
17
18
|
}
|
|
18
19
|
},
|
|
19
20
|
"flat/recommended": [
|
|
@@ -25,7 +26,8 @@ Object.assign(plugin.configs, {
|
|
|
25
26
|
"@tanstack/query/exhaustive-deps": "error",
|
|
26
27
|
"@tanstack/query/no-rest-destructuring": "warn",
|
|
27
28
|
"@tanstack/query/stable-query-client": "error",
|
|
28
|
-
"@tanstack/query/no-unstable-deps": "error"
|
|
29
|
+
"@tanstack/query/no-unstable-deps": "error",
|
|
30
|
+
"@tanstack/query/infinite-query-property-order": "error"
|
|
29
31
|
}
|
|
30
32
|
}
|
|
31
33
|
]
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import { rules } from './rules'\nimport type { ESLint, Linter } from 'eslint'\nimport type { RuleModule } from '@typescript-eslint/utils/ts-eslint'\n\ntype RuleKey = keyof typeof rules\n\ninterface Plugin extends Omit<ESLint.Plugin, 'rules'> {\n rules: Record<RuleKey, RuleModule<any, any, any>>\n configs: {\n recommended: ESLint.ConfigData\n 'flat/recommended': Array<Linter.FlatConfig>\n }\n}\n\nconst plugin: Plugin = {\n meta: {\n name: '@tanstack/eslint-plugin-query',\n },\n configs: {} as Plugin['configs'],\n rules,\n}\n\n// Assign configs here so we can reference `plugin`\nObject.assign(plugin.configs, {\n recommended: {\n plugins: ['@tanstack/eslint-plugin-query'],\n rules: {\n '@tanstack/query/exhaustive-deps': 'error',\n '@tanstack/query/no-rest-destructuring': 'warn',\n '@tanstack/query/stable-query-client': 'error',\n '@tanstack/query/no-unstable-deps': 'error',\n },\n },\n 'flat/recommended': [\n {\n plugins: {\n '@tanstack/query': plugin,\n },\n rules: {\n '@tanstack/query/exhaustive-deps': 'error',\n '@tanstack/query/no-rest-destructuring': 'warn',\n '@tanstack/query/stable-query-client': 'error',\n '@tanstack/query/no-unstable-deps': 'error',\n },\n },\n ],\n})\n\nexport default plugin\n"],"names":[],"mappings":";AAcA,MAAM,SAAiB;AAAA,EACrB,MAAM;AAAA,IACJ,MAAM;AAAA,EACR;AAAA,EACA,SAAS,CAAC;AAAA,EACV;AACF;AAGA,OAAO,OAAO,OAAO,SAAS;AAAA,EAC5B,aAAa;AAAA,IACX,SAAS,CAAC,+BAA+B;AAAA,IACzC,OAAO;AAAA,MACL,mCAAmC;AAAA,MACnC,yCAAyC;AAAA,MACzC,uCAAuC;AAAA,MACvC,oCAAoC;AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import { rules } from './rules'\nimport type { ESLint, Linter } from 'eslint'\nimport type { RuleModule } from '@typescript-eslint/utils/ts-eslint'\n\ntype RuleKey = keyof typeof rules\n\ninterface Plugin extends Omit<ESLint.Plugin, 'rules'> {\n rules: Record<RuleKey, RuleModule<any, any, any>>\n configs: {\n recommended: ESLint.ConfigData\n 'flat/recommended': Array<Linter.FlatConfig>\n }\n}\n\nconst plugin: Plugin = {\n meta: {\n name: '@tanstack/eslint-plugin-query',\n },\n configs: {} as Plugin['configs'],\n rules,\n}\n\n// Assign configs here so we can reference `plugin`\nObject.assign(plugin.configs, {\n recommended: {\n plugins: ['@tanstack/eslint-plugin-query'],\n rules: {\n '@tanstack/query/exhaustive-deps': 'error',\n '@tanstack/query/no-rest-destructuring': 'warn',\n '@tanstack/query/stable-query-client': 'error',\n '@tanstack/query/no-unstable-deps': 'error',\n '@tanstack/query/infinite-query-property-order': 'error',\n },\n },\n 'flat/recommended': [\n {\n plugins: {\n '@tanstack/query': plugin,\n },\n rules: {\n '@tanstack/query/exhaustive-deps': 'error',\n '@tanstack/query/no-rest-destructuring': 'warn',\n '@tanstack/query/stable-query-client': 'error',\n '@tanstack/query/no-unstable-deps': 'error',\n '@tanstack/query/infinite-query-property-order': 'error',\n },\n },\n ],\n})\n\nexport default plugin\n"],"names":[],"mappings":";AAcA,MAAM,SAAiB;AAAA,EACrB,MAAM;AAAA,IACJ,MAAM;AAAA,EACR;AAAA,EACA,SAAS,CAAC;AAAA,EACV;AACF;AAGA,OAAO,OAAO,OAAO,SAAS;AAAA,EAC5B,aAAa;AAAA,IACX,SAAS,CAAC,+BAA+B;AAAA,IACzC,OAAO;AAAA,MACL,mCAAmC;AAAA,MACnC,yCAAyC;AAAA,MACzC,uCAAuC;AAAA,MACvC,oCAAoC;AAAA,MACpC,iDAAiD;AAAA,IACnD;AAAA,EACF;AAAA,EACA,oBAAoB;AAAA,IAClB;AAAA,MACE,SAAS;AAAA,QACP,mBAAmB;AAAA,MACrB;AAAA,MACA,OAAO;AAAA,QACL,mCAAmC;AAAA,QACnC,yCAAyC;AAAA,QACzC,uCAAuC;AAAA,QACvC,oCAAoC;AAAA,QACpC,iDAAiD;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AACF,CAAC;"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare const infiniteQueryFunctions: readonly ["infiniteQueryOptions", "useInfiniteQuery", "useSuspenseInfiniteQuery"];
|
|
2
|
+
export type InfiniteQueryFunctions = (typeof infiniteQueryFunctions)[number];
|
|
3
|
+
export declare const checkedProperties: readonly ["queryFn", "getPreviousPageParam", "getNextPageParam"];
|
|
4
|
+
export declare const sortRules: readonly [readonly [readonly ["queryFn"], readonly ["getPreviousPageParam", "getNextPageParam"]]];
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const infiniteQueryFunctions = [
|
|
2
|
+
"infiniteQueryOptions",
|
|
3
|
+
"useInfiniteQuery",
|
|
4
|
+
"useSuspenseInfiniteQuery"
|
|
5
|
+
];
|
|
6
|
+
const sortRules = [
|
|
7
|
+
[["queryFn"], ["getPreviousPageParam", "getNextPageParam"]]
|
|
8
|
+
];
|
|
9
|
+
export {
|
|
10
|
+
infiniteQueryFunctions,
|
|
11
|
+
sortRules
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +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\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;"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
import { ExtraRuleDocs } from '../../types';
|
|
3
|
+
export declare const name = "infinite-query-property-order";
|
|
4
|
+
export declare const rule: ESLintUtils.RuleModule<string, readonly unknown[], ExtraRuleDocs, ESLintUtils.RuleListener>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
2
|
+
import { getDocsUrl } from "../../utils/get-docs-url.js";
|
|
3
|
+
import { detectTanstackQueryImports } from "../../utils/detect-react-query-imports.js";
|
|
4
|
+
import { sortDataByOrder } from "./infinite-query-property-order.utils.js";
|
|
5
|
+
import { infiniteQueryFunctions, sortRules } from "./constants.js";
|
|
6
|
+
const createRule = ESLintUtils.RuleCreator(getDocsUrl);
|
|
7
|
+
const infiniteQueryFunctionsSet = new Set(infiniteQueryFunctions);
|
|
8
|
+
function isInfiniteQueryFunction(node) {
|
|
9
|
+
return infiniteQueryFunctionsSet.has(node);
|
|
10
|
+
}
|
|
11
|
+
const name = "infinite-query-property-order";
|
|
12
|
+
const rule = createRule({
|
|
13
|
+
name,
|
|
14
|
+
meta: {
|
|
15
|
+
type: "problem",
|
|
16
|
+
docs: {
|
|
17
|
+
description: "Ensure correct order of inference sensitive properties for infinite queries",
|
|
18
|
+
recommended: "error"
|
|
19
|
+
},
|
|
20
|
+
messages: {
|
|
21
|
+
invalidOrder: "Invalid order of properties for `{{function}}`."
|
|
22
|
+
},
|
|
23
|
+
schema: [],
|
|
24
|
+
hasSuggestions: true,
|
|
25
|
+
fixable: "code"
|
|
26
|
+
},
|
|
27
|
+
defaultOptions: [],
|
|
28
|
+
create: detectTanstackQueryImports((context) => {
|
|
29
|
+
return {
|
|
30
|
+
CallExpression(node) {
|
|
31
|
+
if (node.callee.type !== AST_NODE_TYPES.Identifier) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const infiniteQueryFunction = node.callee.name;
|
|
35
|
+
if (!isInfiniteQueryFunction(infiniteQueryFunction)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const argument = node.arguments[0];
|
|
39
|
+
if (argument === void 0 || argument.type !== "ObjectExpression") {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const allProperties = argument.properties;
|
|
43
|
+
if (allProperties.length < 2) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const properties = allProperties.flatMap((p) => {
|
|
47
|
+
if (p.type === AST_NODE_TYPES.Property && p.key.type === AST_NODE_TYPES.Identifier) {
|
|
48
|
+
return { name: p.key.name, property: p };
|
|
49
|
+
} else if (p.type === AST_NODE_TYPES.SpreadElement) {
|
|
50
|
+
if (p.argument.type === AST_NODE_TYPES.Identifier) {
|
|
51
|
+
return { name: p.argument.name, property: p };
|
|
52
|
+
} else {
|
|
53
|
+
throw new Error("Unsupported spread element");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return [];
|
|
57
|
+
});
|
|
58
|
+
const sortedProperties = sortDataByOrder(properties, sortRules, "name");
|
|
59
|
+
if (sortedProperties === null) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
context.report({
|
|
63
|
+
node: argument,
|
|
64
|
+
data: { function: node.callee.name },
|
|
65
|
+
messageId: "invalidOrder",
|
|
66
|
+
fix(fixer) {
|
|
67
|
+
const sourceCode = context.sourceCode;
|
|
68
|
+
const text = sortedProperties.reduce(
|
|
69
|
+
(sourceText, specifier, index) => {
|
|
70
|
+
let text2 = "";
|
|
71
|
+
if (index < allProperties.length - 1) {
|
|
72
|
+
text2 = sourceCode.getText().slice(
|
|
73
|
+
allProperties[index].range[1],
|
|
74
|
+
allProperties[index + 1].range[0]
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
return sourceText + sourceCode.getText(specifier.property) + text2;
|
|
78
|
+
},
|
|
79
|
+
""
|
|
80
|
+
);
|
|
81
|
+
return fixer.replaceTextRange(
|
|
82
|
+
[allProperties[0].range[0], allProperties.at(-1).range[1]],
|
|
83
|
+
text
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
})
|
|
90
|
+
});
|
|
91
|
+
export {
|
|
92
|
+
name,
|
|
93
|
+
rule
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=infinite-query-property-order.rule.js.map
|
package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.rule.js.map
ADDED
|
@@ -0,0 +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 { 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;"}
|
|
@@ -0,0 +1 @@
|
|
|
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;
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
);
|
|
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();
|
|
29
|
+
const result = data.map((item) => {
|
|
30
|
+
if (getSubsetIndex(item[key], orderSets) !== null) {
|
|
31
|
+
const sortedItem = inOrderIterator.next().value;
|
|
32
|
+
if (sortedItem[key] !== item[key]) {
|
|
33
|
+
wasResorted = true;
|
|
34
|
+
}
|
|
35
|
+
return sortedItem;
|
|
36
|
+
}
|
|
37
|
+
return item;
|
|
38
|
+
});
|
|
39
|
+
if (!wasResorted) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
sortDataByOrder
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=infinite-query-property-order.utils.js.map
|
package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.utils.js.map
ADDED
|
@@ -0,0 +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 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;"}
|
|
@@ -18,7 +18,7 @@ const rule = createRule({
|
|
|
18
18
|
meta: {
|
|
19
19
|
type: "problem",
|
|
20
20
|
docs: {
|
|
21
|
-
description: "Disallow putting the result of
|
|
21
|
+
description: "Disallow putting the result of query hooks directly in a React hook dependency array",
|
|
22
22
|
recommended: "error"
|
|
23
23
|
},
|
|
24
24
|
messages: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"no-unstable-deps.rule.js","sources":["../../../../src/rules/no-unstable-deps/no-unstable-deps.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'\nimport type { TSESTree } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from '../../types'\n\nexport const name = 'no-unstable-deps'\n\nexport const reactHookNames = ['useEffect', 'useCallback', 'useMemo']\nexport const useQueryHookNames = [\n 'useQuery',\n 'useSuspenseQuery',\n 'useQueries',\n 'useSuspenseQueries',\n 'useInfiniteQuery',\n 'useSuspenseInfiniteQuery',\n]\nconst allHookNames = ['useMutation', ...useQueryHookNames]\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow putting the result of
|
|
1
|
+
{"version":3,"file":"no-unstable-deps.rule.js","sources":["../../../../src/rules/no-unstable-deps/no-unstable-deps.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'\nimport type { TSESTree } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from '../../types'\n\nexport const name = 'no-unstable-deps'\n\nexport const reactHookNames = ['useEffect', 'useCallback', 'useMemo']\nexport const useQueryHookNames = [\n 'useQuery',\n 'useSuspenseQuery',\n 'useQueries',\n 'useSuspenseQueries',\n 'useInfiniteQuery',\n 'useSuspenseInfiniteQuery',\n]\nconst allHookNames = ['useMutation', ...useQueryHookNames]\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow putting the result of query hooks directly in a React hook dependency array',\n recommended: 'error',\n },\n messages: {\n noUnstableDeps: `The result of {{queryHook}} is not referentially stable, so don't pass it directly into the dependencies array of {{reactHook}}. Instead, destructure the return value of {{queryHook}} and pass the destructured values into the dependency array of {{reactHook}}.`,\n },\n schema: [],\n },\n defaultOptions: [],\n\n create: detectTanstackQueryImports((context) => {\n const trackedVariables: Record<string, string> = {}\n const hookAliasMap: Record<string, string> = {}\n\n function getReactHook(node: TSESTree.CallExpression): string | undefined {\n if (node.callee.type === 'Identifier') {\n const calleeName = node.callee.name\n // Check if the identifier is a known React hook or an alias\n if (reactHookNames.includes(calleeName) || calleeName in hookAliasMap) {\n return calleeName\n }\n } else if (\n node.callee.type === 'MemberExpression' &&\n node.callee.object.type === 'Identifier' &&\n node.callee.object.name === 'React' &&\n node.callee.property.type === 'Identifier' &&\n reactHookNames.includes(node.callee.property.name)\n ) {\n // Member expression case: `React.useCallback`\n return node.callee.property.name\n }\n return undefined\n }\n\n function collectVariableNames(\n pattern: TSESTree.BindingName,\n queryHook: string,\n ) {\n if (pattern.type === AST_NODE_TYPES.Identifier) {\n trackedVariables[pattern.name] = queryHook\n }\n }\n\n return {\n ImportDeclaration(node: TSESTree.ImportDeclaration) {\n if (\n node.specifiers.length > 0 &&\n node.importKind === 'value' &&\n node.source.value === 'React'\n ) {\n node.specifiers.forEach((specifier) => {\n if (\n specifier.type === AST_NODE_TYPES.ImportSpecifier &&\n reactHookNames.includes(specifier.imported.name)\n ) {\n // Track alias or direct import\n hookAliasMap[specifier.local.name] = specifier.imported.name\n }\n })\n }\n },\n\n VariableDeclarator(node) {\n if (\n node.init !== null &&\n node.init.type === AST_NODE_TYPES.CallExpression &&\n node.init.callee.type === AST_NODE_TYPES.Identifier &&\n allHookNames.includes(node.init.callee.name)\n ) {\n collectVariableNames(node.id, node.init.callee.name)\n }\n },\n CallExpression: (node) => {\n const reactHook = getReactHook(node)\n if (\n reactHook !== undefined &&\n node.arguments.length > 1 &&\n node.arguments[1]?.type === AST_NODE_TYPES.ArrayExpression\n ) {\n const depsArray = node.arguments[1].elements\n depsArray.forEach((dep) => {\n if (\n dep !== null &&\n dep.type === AST_NODE_TYPES.Identifier &&\n trackedVariables[dep.name] !== undefined\n ) {\n const queryHook = trackedVariables[dep.name]\n context.report({\n node: dep,\n messageId: 'noUnstableDeps',\n data: {\n queryHook,\n reactHook,\n },\n })\n }\n })\n }\n },\n }\n }),\n})\n"],"names":[],"mappings":";;;AAMO,MAAM,OAAO;AAEb,MAAM,iBAAiB,CAAC,aAAa,eAAe,SAAS;AAC7D,MAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACA,MAAM,eAAe,CAAC,eAAe,GAAG,iBAAiB;AACzD,MAAM,aAAa,YAAY,YAA2B,UAAU;AAE7D,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,gBAAgB;AAAA,IAClB;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAAA,EACA,gBAAgB,CAAC;AAAA,EAEjB,QAAQ,2BAA2B,CAAC,YAAY;AAC9C,UAAM,mBAA2C,CAAA;AACjD,UAAM,eAAuC,CAAA;AAE7C,aAAS,aAAa,MAAmD;AACnE,UAAA,KAAK,OAAO,SAAS,cAAc;AAC/B,cAAA,aAAa,KAAK,OAAO;AAE/B,YAAI,eAAe,SAAS,UAAU,KAAK,cAAc,cAAc;AAC9D,iBAAA;AAAA,QACT;AAAA,MACF,WACE,KAAK,OAAO,SAAS,sBACrB,KAAK,OAAO,OAAO,SAAS,gBAC5B,KAAK,OAAO,OAAO,SAAS,WAC5B,KAAK,OAAO,SAAS,SAAS,gBAC9B,eAAe,SAAS,KAAK,OAAO,SAAS,IAAI,GACjD;AAEO,eAAA,KAAK,OAAO,SAAS;AAAA,MAC9B;AACO,aAAA;AAAA,IACT;AAES,aAAA,qBACP,SACA,WACA;AACI,UAAA,QAAQ,SAAS,eAAe,YAAY;AAC7B,yBAAA,QAAQ,IAAI,IAAI;AAAA,MACnC;AAAA,IACF;AAEO,WAAA;AAAA,MACL,kBAAkB,MAAkC;AAEhD,YAAA,KAAK,WAAW,SAAS,KACzB,KAAK,eAAe,WACpB,KAAK,OAAO,UAAU,SACtB;AACK,eAAA,WAAW,QAAQ,CAAC,cAAc;AAEnC,gBAAA,UAAU,SAAS,eAAe,mBAClC,eAAe,SAAS,UAAU,SAAS,IAAI,GAC/C;AAEA,2BAAa,UAAU,MAAM,IAAI,IAAI,UAAU,SAAS;AAAA,YAC1D;AAAA,UAAA,CACD;AAAA,QACH;AAAA,MACF;AAAA,MAEA,mBAAmB,MAAM;AAErB,YAAA,KAAK,SAAS,QACd,KAAK,KAAK,SAAS,eAAe,kBAClC,KAAK,KAAK,OAAO,SAAS,eAAe,cACzC,aAAa,SAAS,KAAK,KAAK,OAAO,IAAI,GAC3C;AACA,+BAAqB,KAAK,IAAI,KAAK,KAAK,OAAO,IAAI;AAAA,QACrD;AAAA,MACF;AAAA,MACA,gBAAgB,CAAC,SAAS;;AAClB,cAAA,YAAY,aAAa,IAAI;AACnC,YACE,cAAc,UACd,KAAK,UAAU,SAAS,OACxB,UAAK,UAAU,CAAC,MAAhB,mBAAmB,UAAS,eAAe,iBAC3C;AACA,gBAAM,YAAY,KAAK,UAAU,CAAC,EAAE;AAC1B,oBAAA,QAAQ,CAAC,QAAQ;AAEvB,gBAAA,QAAQ,QACR,IAAI,SAAS,eAAe,cAC5B,iBAAiB,IAAI,IAAI,MAAM,QAC/B;AACM,oBAAA,YAAY,iBAAiB,IAAI,IAAI;AAC3C,sBAAQ,OAAO;AAAA,gBACb,MAAM;AAAA,gBACN,WAAW;AAAA,gBACX,MAAM;AAAA,kBACJ;AAAA,kBACA;AAAA,gBACF;AAAA,cAAA,CACD;AAAA,YACH;AAAA,UAAA,CACD;AAAA,QACH;AAAA,MACF;AAAA,IAAA;AAAA,EACF,CACD;AACH,CAAC;"}
|
package/dist/esm/rules.js
CHANGED
|
@@ -2,11 +2,13 @@ import { name, rule } from "./rules/exhaustive-deps/exhaustive-deps.rule.js";
|
|
|
2
2
|
import { name as name$1, rule as rule$1 } from "./rules/stable-query-client/stable-query-client.rule.js";
|
|
3
3
|
import { name as name$2, rule as rule$2 } from "./rules/no-rest-destructuring/no-rest-destructuring.rule.js";
|
|
4
4
|
import { name as name$3, rule as rule$3 } from "./rules/no-unstable-deps/no-unstable-deps.rule.js";
|
|
5
|
+
import { name as name$4, rule as rule$4 } from "./rules/infinite-query-property-order/infinite-query-property-order.rule.js";
|
|
5
6
|
const rules = {
|
|
6
7
|
[name]: rule,
|
|
7
8
|
[name$1]: rule$1,
|
|
8
9
|
[name$2]: rule$2,
|
|
9
|
-
[name$3]: rule$3
|
|
10
|
+
[name$3]: rule$3,
|
|
11
|
+
[name$4]: rule$4
|
|
10
12
|
};
|
|
11
13
|
export {
|
|
12
14
|
rules
|